MySQL从基础到高级篇二

MySQL从基础到高级篇二

  1. 首先在之前的数据表后再创建两张表供后面操作
1、teacher 表
	CREATE TABLE `teacher` (
		  `Id` int(11) NOT NULL AUTO_INCREMENT,
		  `last_name` varchar(255) DEFAULT NULL COMMENT '名字字段',
		  `age` varchar(255) DEFAULT NULL COMMENT '年龄字段',
		  PRIMARY KEY (`Id`)
		) ENGINE=MyISAM AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='老师数据表';

2、student 表
	CREATE TABLE `student` (
		  `Id` int(11) NOT NULL AUTO_INCREMENT,
		  `last_name` varchar(255) DEFAULT NULL COMMENT '学生名字',
		  `sex` varchar(255) DEFAULT NULL COMMENT '学生性别',
		  `tech_id` int(11) DEFAULT NULL,
		  PRIMARY KEY (`Id`)
		) ENGINE=MyISAM AUTO_INCREMENT=8 DEFAULT CHARSET=utf8 COMMENT='一个学生表';

3、工资级别表
	CREATE TABLE `job_grade` (
		  `grade_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '级别编号',
		  `grade_level` varchar(255) DEFAULT NULL COMMENT '级别水平',
		  `lowest_sal` int(11) DEFAULT NULL COMMENT '最低工资标准',
		  `highest_sal` int(11) DEFAULT NULL COMMENT '最高工资标准',
		  PRIMARY KEY (`grade_id`)
		) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='工作级别表';
  1. 连接查询
    含义:又称多表查询,当查询的字段来自于多个表时,就会用到连接查询
    笛卡尔乘积现象:表1 有m 行,表2 有n 行,结果=m*n 行
    发生原因:没有有效的连接条件
    如何避免:添加有效的连接条件
分类:
	①按年份分类:
		sql92标准:仅仅支持内连接
		sql96标准【推荐】:支持内连接+外连接(左外和右外)+交叉连接
	②按功能分类:
		内连接:
			等值连接
			非等值连接
			自连接
		外连接:
			左外连接
			右外连接
			全外连接
		交叉连接

一、sql92 标准
	特点:
			① 多表等值连接的结果为多表的交集部分
			② n 表连接,至少需要n-1 个连接条件
			③ 多表的顺序没有要求
			④ 一般需要为表放别名
			⑤ 可以搭配前面介绍的所有子句使用,比如:排序、分组、筛选

	1、等值连接
	#案例1、查询学生名和对应的老师名
	——select student.last_name as 学生名字, teacher.last_name as 老师名字
			from student, teacher
			where student.tech.id=teacher.id;
	#案例2、查询员工名和部门名称
	——select e.last_name as 员工名, e.department_name as 部门名称
			from employees as e, departments as d
			where e.department_id=d.department_id;
			
		1.1、为表起别名
		特性:
			① 提高了语句的简洁度
			② 区分多个重名字段
		注意:如果为数据表起了别名,则查询的字段就不能使用原来的表名去限定
		#案例:查询员工名、工种号、工种名
		——select e.last_name as 员工名, e.job_id as 工种号, j.job_name as 工种名
				from employees as e, jobs as j
				where e.job_id=j.job_id;
				
		1.2、查询表的顺序可以调换
		#案例:查询员工名、工种号、工种名
		——select e.last_name as 员工名, e.job_id as 工种号, j.job_name as 工种名
				from jobs as j, employees as e
				where e.job_id=j.job_id;
	
		1.3、添加筛选条件
		#案:1:查询有奖金的员工名、部门名
		——select e.last_name as 员工名, d.department_name as 部门名
				from employees as e, departments as d
				where e.department_id=d.department_id
				and e.commission_pet is not null;
		#案例2:查询城市名中第二个字符为‘o’的部门名和城市名
		——select d.department_name as 部门名, l.city as 城市名
				from departments as d, location as l
				where l.city like '_o%';
		
		1.4、添加分组条件
		#案例1:查询每个城市的部门个数
		——select count(*) as 部门个数, city as 城市名
				from departments as d, locations as l
				where d.location_id=l.location_id
				group by l.city;
		#案例2:查询有奖金的每个部门的部门名和部门的领导编号和该部门的最低工资
		——select department_name as 部门名, d.manager_id as 部门领导编号, min(e.salary) as 最低工资
				from departments as d, employees as e
				where d.department_id=e.department_id
				and commission_pet is not null
				group by department_name, d.manager_id;
		#案例3:查询每个工种的工种名和员工个数,并且按员工个数降序
		——select e.jobs_id as 工种名, count(*) as 员工个数
				from employees as e, jobs as j
				where e.jobs_id=j.jobs_id
				group by jobs_name
				order by count(*) desc;
	
		1.5、实现多表连接查询
		#案例1:查询员工名、部门名和所在的城市
		——select last_name as 员工名, d.department_id as 部门名, city as 城市名
				from employees as e, departments as d, locations as l
				where e.department_id=d.department_id
				and d.location_id=l.location_id

	2、非等值连接
	#案例1:查询员工的工资和工资级别
	——select salary as 工资, grade_level as 工资级别
			from employees as e, job_grade as j_g
			where e.salary between j_g.loweest_sal and j_g.highest_sal;

	3、自连接
	#案例:查询员工名和领导名
	——select last_name as 员工名, empoyee_id as 员工编号, last_name as 领导名称, employee_id as 领导编号
			from employees as e, employees as m
			where e.employee_id=m.employee_id;

练习题
	#案例1:显示员工表的最大工资,工资平均值
	——select max(salary) as 最大工资, avg(salary) as 平均工资
			from employees;
	#案例2:查询员工表的employee_id,job_id,last_name,按department_id 降序,salary 升序
	——select employee_id as 员工编号, job_id as 工作编号, last_name as 员工姓名
			from employees
			order by department_id desc, salary asc;
	#案例3:查询员工表的job_id 中包含 a 和 e 的,并且a 在e 的前面
	——select job_id as 工种编号, employee_id as 员工编号, employee_name as 员工姓名
			from employees
			where job_id like '%a%e%';
	#案例4:已知表 student,里面有 id(学号),name,grade_id(年级编号)
					已知表grade,里面有id(年级编号),name(年级名)
					已知表result,里面有id,score,studentNo(学号)
					要求查询学生姓名、年级名、成绩
	——select s.name as 学生姓名, g.name as 年级名, score as 成绩
			from student as s, grade as g, result as r
			where s.grade_id=g.id
			and s.id=r.studentNo;
	#按例5:显示当前日期,以及去除前后隔空,截取字符串的函数
	——select now();
	——select trim(startIndex, str);
	——select substr(str, startIndex, length);
	#案例6:显示所有员工的姓名、部门号和部门名称
	——select employee_id as 员工姓名, department_id as 员工编号, department_name as 部门名称
			from employees as e, departments as d
			where e.department_id=d.department_id;
	#案例7:查询90号部门员工的job_id 和90 号部门的location_id
	——select e.job_id as 工种编号, d.location_id as 位置编号, e.department_id as 部门编号
			from employees as e, departments as d
			where e.department_id=d.department_id
			and e.department_id=90;
	#案例8:选择所有奖金的员工的last_name、job_id、department_name、location_id、city
	——select e.last_name as 员工姓名, e.job_id as 工种编号, d.department_name as 部门名称, l.location_id as 位置编号, city as 城市名
			from employees as e, departments as d, locations as l
			where e.department_id=d.department_id
			and d.location_id=l.location_id
			and commission_pet is not null;
	#案例9:选择city 在Toronto 工作的员工的last_name、job_id、department_id、department_name
	——select e.last_name as 员工姓名, e.job_id as 工种编号, d.department_id as 部门编号, d.department_name as 部门名称
			from employees as e, departments as d, locations as l
			where e.department_id=d.department_id
			and d.department_id=l.department_id
			and city='Toronto'
	#案例10:查询每个工种、每个部门的部门名、工种名和最低工资
	——select department_name as 部门名称, job_name as 工种名称, min(salary) as 最低工资
			from departments as d, employees as e, jobs as j
			where d.department_id=e.department_id
			and e.job_id=j.job_id
			group by department_name;
	#案例11:查询每个国家下的部门个数大于2 的国家编号
	——select country_id as 国家编号, count(*) as 部门个数
			from locations as l, departments as d
			where l.location_id=d.location_id
			group by country_id
			having count(*)>2;
	#案例12:选择指定员工的姓名,员工号、以及他的领导姓名和编号,结果类似于下面格式
			员工姓名 				员工编号					领导姓名				领导编号
			kocahhar				1001						King						100
	——select e.last_name as 员工姓名, e.employee_id as 员工编号, m.last_name as 领导姓名, m.employee_id as 领导编号
	from employees as e, employees as m
	where e.manager_id=m.employee_id
	and last_name='kocahhar';
	
二、sql99 标准
语法:
		select 查询列表
		from 表1 别名 【连接类型】
		join 表2 别名
		on 连接条件
		【where 筛选条件】	
		【group by 分组条件】
		【having 筛选条件】
		【order by 排序列表】
		【limit 偏移, 条目数】
分类:
		内连接(★):inner
		外连接
				左外连接(★):left【outer】
				右外连接(★):right【outer】
				全外连接:full【outer】
		交叉连接:cross
	
1、内连接
	语法:
			select 查询列表
			from 表1 别名
			inner join 表2 别名
			on 连接条件
			【where 筛选条件】	
			【group by 分组条件】
			【having 筛选条件】
			【order by 排序列表】
			【limit 偏移, 条目数】
	
	特点:
		① 添加排序、分组、筛选
		② inner 可以省略
		③ 筛选条件可以放在where 后面,连接条件放在on 后面,提高分离性,便于阅读
		④ inner join 连接和sql92 语法中的等值连接效果一样的,都是查询多张表的交集
		⑤ n 表连接至少需要n-1 个连接条件
			
	①等值连接
	#案例1:查询员工名、部门名(调换位置)
	——select employee_name as 员工名, department_name as 部门名
			from employees as e
			inner join department_name as d
			on e.department_id=d.deparment_id
	#案例2:查询名字中包含‘e’的员工名和工种名
	——select last_name as 员工名, job_name as 工种名
			from employees as e
			inner join jobs as j
			on e.job_id=j.job_id
			where last_name like '%e%';
	#案例3:查询部门个数>3 的城市名和部门个数(分组+筛选)
	——select city as 城市名称, count(*) as 部门个数
			from departments as d 
			inner join locations as l
			on d.location_id=l.location_id
			group by city
			having count(*)>3;
	#案例4:查询哪个部门的部门员工个数>3 的部门名和员工个数,并按个数降序(排序)
	——select department_name as 部门名称, count(*) as 员工个数
			from employees as e
			inner join departments as d
			on e.department_id=d.department_id
			group by d.department_id
			having count(*)>3
			order by count(*) desc;
	#案例5:查询员工名、部门名、工种名,并按照部门名降序
	——select last_name as 员工名, department_name as 部门名称, job_name as 工种名称
			from employees as e
			inner join departments as d on e.department_id=d.department_id
			inner join  jobs as j on e.job_id=j.job_id
			order by 部门名称 desc;
	
	② 非等值连接
	#案例1:查询员工的工资级别
	——select salary as 工资, grade_level as 工资级别
			from employees as e
			inner join job_grade as j_g
			on e.salary between j_g.lowest_sal and highest_level;
	#案例2:查询每个工资级别的员工个数>3,并且按工资级别降序
	——select count(*) as 员工个数, grade_level as 工资级别
			from employees e
			inner join job_grade as j_g
			on e.salary between j_g.lowest_sal and highest_sal
			group by grade_level
			having count(*)>3
			order by count(*) desc;
	
	③ 自连接
	#案例:查询员工的名字包含‘k’的员工名字、领导名字
	——select last_name as 员工姓名, manager_name as 领导名字
			from employees as e
			inner join employees as m
			on e.manager_id=m.employee_id;
			where e.last_name like '%k%';

2、外连接
	应用场景:用于查询一个表中有,另一张表中没有的记录
	语法:
			select 查询列表
			from 表1 别名
			left/right/full 【outer】 join 表2 别名
			on 连接条件
			【where 筛选条件】	
			【group by 分组条件】
			【having 筛选条件】
			【order by 排序列表】
			【limit 偏移, 条目数】
	特点:
			①外连接的查询结果为主表中的所有记录
			——如果从表中有和它匹配的,则显示匹配的值
			——如果从表中没有和它匹配的,则显示null
			——外连接查询结果=内连接结果+主表中有而从表中没有的记录
			② 左外连接:left join左边的是主表
				右外连接:right join右边的是主表
			③左外连接和右外连接交换两个表的顺序,可以实现同样的效果
			④ 全外连接=内连接的结果+表1中有但表2中没有的+表2中有但表1中没有的
	
	#案例1:查询学生的老师名字不在老师表的学生名字(左外连接)
	——select s.last_name as 学生姓名, t.last_name as 老师姓名
			from student as s
			left outer join teacher as t
			on s.tech_id=t.id
			where t.last_name is null;
	#案例2:查询学生的老师名字不在老师表的学生名字(右外连接)
	——select s.last_name as 学生姓名
			from student as s
			right outer join teacher as t
			on t.id=s.tech_id
			where t.last_name is null;
	#案例3:查询哪个部门没有员工
	——select department_name as 部门名称
			from departments as d
			left outer employees as e
			on d.department_Id=e.department_id
			where e.department_id is null;

练习题
	#案例1:查询编号>4的学生的老师信息,如果有则列出详细,如果没有,用null填充
	——select s.id as 学生编号, t.*
			from student as s
			left outer join teacher as t
			on s.tech_id=t.id
			where s.id>4
	#案例2:查询哪个城市没有部门
	——select city as 城市名称
			from locations as l
			left outer join departments as d
			on l.location_id=d.location_id
			where d.location_id is null;
	#案例3:查询部门名为SAL或IT 的员工信息
	——select department_name as 部门名称, e.*
			from departments as d
			left outer join employees as e
			on d.department_id=e.department_id
			where department_name in('SAL', 'IT');
			
  1. 子查询
    含义:
    嵌套在其他语句中的select 语句,称为子查询或内查询
    外部的查询语句,称为主查询或外查询
    外部的语句可以是insert、update、delete、select 等,一般insert 作为外面语句偏移
    分类:
    按子查询出现的位置:
    select 后面:
    仅仅支持标量子查询
    from 后面:
    支持表子查询
    where 或having 后面:
    标量子查询(单行)
    列子查询(多行)
    行子查询
    exists 后面(相关子查询)
    表子查询
    按结果集的行列数不同:
    标量子查询(结果集只有一行一列)
    列子查询(结果只有多行一列)
    行子查询(结果集有一行多列)
    表子查询(结果集一般为多行多列)
一、where或having 后面
1、标量子查询(单行子查询)
2、列子查询(多行子查询)
3、行子查询(多列子查询)
特点:
	① 子查询放在小括号内
	② 子查询一般放在条件的右侧
	③ 标量子查询,一般搭配着单行操作符使用(>、<、>=、<=、=、<>)
	④ 列子查询,一般搭配着多行操作符使用(in、any/some、all)
	⑤ 子查询的执行优先于主查询执行,主查询的条件用到了子查询的结果

#1、标量子查询
	#案例1:谁的工资比Abel 高
	——select last_name as 员工名称, salary as 工资
			from employees
			where salary>(select salary from employees where last_name='Abel');
	#案例2:返回job_id 与员工编号为123 相同,salary 比员工编号为134 多的员工姓名,job_id 和工资
	——select last_name as 员工姓名, job_id as 工种编号, salary as 工资
			from employees
			where job_id=(select job_id from employees where employee_id=123)
			and salary>(select salary from employees where employee_id=134);
	#案例3:返回公司工资最少的员工信息的last_name, job_id 和salary
	——select last_name as 员工姓名, job_id as 工种编号, salary as 工资
			from employees
			where salary=(select min(salary) from employees);
	#案例4:查询最低工资大于部门编号为50 最低工资的部门编号和其最低工资
			①部门编号为50 的最低工资
			②每个部门的最低工资
			③ 在②基础上满足min(salary)>①
	——select department_id as 部门编号, salary as 最低工资
			from employees
			group by department_id;
			having min(salary)>(select min(salary) from employees where department_id=50)
	#2、列子查询(多行子查询)
	#案例1:返回location_id 是1400或1800 的部门中的所有员工姓名
	——select last_name as 员工姓名
			from employees
			where department_id in(
							select distinct department_id 
							from departments 
							where location_id in(1400, 1800)
						);
	#案例2:返回其他工种中比job_id 为‘IT_PROG’ 工种任一工资都低的员工的员工编号、姓名、job_id 以及salary
			①job_id 为‘IT_PROG’ 部门的任一工资
			——select distinct salary from employees where job_id='IT_PROG';
			②查询员工的员工编号、姓名、job_id 以及salary,salary<(①)的任意一个
			——select employee_id as 员工编号, last_name as 员工姓名, job_id as 工种编号, salary as 工资
					from employees 
					where salary'IT_PROG';
	#案例3:返回其他工种中比job_id 为‘IT_PROG’ 工种所有工资都低的员工的员工编号、姓名、job_id 以及salary
	——select employee_id as 员工编号, last_name as 员工姓名, job_id as 工种编号, salary as 工资
			from employees
			where salary'IT_PROG';

3、行子查询(结果集一行多列或多行多列)
	#案例1:查询员工编号最小并且工资最高的员工信息
	——select *
			from employees
			where (employee_id, salary)=(
				select min(employee_id), max(salary)
				from employees
			);

二、select 后面(仅仅支持标量子查询)
#案例1:查询每个部门的员工个数
——select d.*, (
			select count(*)
			from employees as e
			where e.department_id=d.department_id
		)  as个数
		from departments as d;
#案例2:查询员工编号=120的部门名称
——select (
			select department_name
			from departments as d
			inner join employees as e
			on d.department_id=e.department_id
			where e.employee_id=120 
		) as 部门名称;
		
三、from 后面
#案例1:查询每个部门的平均工资的工资等级
	①查询每个部门的平均工资和部门编号(作为一个新表avg_dep)
	②平均工资所在的工资等级(与新表关联,采用内连接中的非等值连接)
——select avg_dep.*, grade_level as 工资等级
		from (
			select avg(salary) as av, department_id as dp
			from employees as e
			group by e.department_id
		) as avg_dep
		inner join job_grade as j_g
		on avg_dep.av between lowest_sal and highest_sal;

四、exists 后面(相关子查询)
#案例1:查询部门有员工的部门名称
——select department_name as 部门名称
		from departments as d
		where exists(
			select *
			from employees as e
			where e.department_id=d.department_id
		);
#案例2:查询在老师表中没有指导老师的学生信息
——select *
		from student as s
		where not exists(
			select *
			from teacher as t
			where t.id=s.tech_id
		);

练习题
	#案例1:查询和学生名为‘张无忌’相同老师的学生姓名和性别
			①查询学生姓名为‘张无忌’的老师ID
			②查询员工姓名和工资,部门编号=①
	——select last_name as 学生姓名, sex as 学生性别
			from student as s
			where s.tech_id=(
				select st.tech_id
				from student as st
				where last_name='张无忌'
			);
	#案例2:查询分数比所有学生平均分数高的学生编号、姓名和分数
	——select s.id as 学生编号, s.last_name as 学生姓名, s.score as 学生分数
			from student as s
			where score>(
				select avg(score)
				from student
			);
	#案例3:查询各指导老师组中学生分数比本指导教师组内学生平均分数高的学生的学生号、姓名和分数
			①查询每个指导组的平均分数
			②查询每个指导组的学生分数
			③在 ① 的基础上和② 做比较
	——select score as 学生分数, s.last_name as 学生姓名, tech_id as 指导组编号
			from student as s
			inner join teacher as t
			on s.tech_id=t.id
			where score>(
			      select avg(score)
			      from student as st
			      group by st.tech_id
			      having t.id=st.tech_id
			);
	#案例4:查询和姓名中包含字母‘刘’ 的学生在相同指导教师组的学生编号和姓名
			① 查询名字含字母‘刘’ 的学生的指导组编号
			② 查询在① 为基础上的指导组内的学生信息
	——select *
			from student
			where tech_id in(
			      select tech_id
			      from student as s
			      where last_name like '%刘%'
			);
	#案例5:查询在教师组的任教课程 为‘语文’ 的指导组的学生的编号
	——select s.id, tech_id
			from student as s
			inner join(
			      select t.id 
			      from teacher as t 
			      where course='语文'
			) as th
			on s.tech_id=th.id
	#案例6:查询指导教师姓名为‘赵六’的学生姓名和分数
	——select s.last_name as 学生姓名, score as 分数
			from student as s
			where tech_id in(
			      select t.id
			      from teacher as t
			      where t.last_name='赵六'
			);
	#案例7:查询分数最高的学生的姓名,要求last_name 和sex 显示为一列,列名为姓名
	——select concat(last_name, sex) as 姓名
			from student
			where score=(
			      select max(score)
			      from student
			);
	#案例8:查询各个指导组中平均分数最低的指导老师信息
	——select te.*
			from teacher as te
			where id=(
			      select tech_id
			      from student as s
			      inner join teacher as t
			      where tech_id=t.id
			      group by tech_id
			      order by avg(score)
			      limit 0,1
			);
	#案例9:查询平均分数最低的指导组信息和该指导组的平均分数
			① 先查询出最低指导组的学生平均分数和指导组ID
			② 利用① 的结果作为从表和teacher 表建立内连接关联
			③ 在② 基础上查询teacher 表中id=从表中ID 的信息
	——select t.*, ag_tid.ag
			from teacher as t
			inner join (
			      select avg(score) as ag, tech_id
			      from student as s
			      inner join teacher as t
			      where tech_id=t.id
			      group by tech_id
			      order by avg(score)
			      limit 1
			) as ag_tid
			on t.id=ag_tid.tech_id
	#案例10:查询平均分数最高的 指导组老师信息
	——select *
			from teacher
			where id=(
			      select tech_id
			      from student as s
			      inner join teacher as t
			      where tech_id=t.id
			      group by tech_id
			      order by avg(score) desc
			      limit 1
			);
	#案例11:查询平均分数高于总学生平均分数的指导组信息
			① 获得所有学生的平均分数
			② 获得所有指导组的学生平均分数
			③ 获取指导组平均分数比学生平均分数高的指导组ID
			④ 在teacher 表中查询id in(③ 结果)的信息
	——select *			##④
			from teacher
			where id in(
			      select tech_id		##②③
			      from student as s
			      inner join teacher as t
			      where tech_id=t.id
			      group by tech_id
			      having avg(score)>(
			        select avg(score)			##①
			        from student
			      )
			);
	#案例12:查询公司所有 manger 的详细信息
	——select *
			from employees as e
			where e.employee.id in(
				select distinct employee_id
				from employees
				where manager_id is not null
			);
	#案例13:各个指导组中最高的分数中最低那个指导组的最低分数是多少
			① 查询各个指导组的学生最高分数的tech_id
			② 查询student 表中以① 结果作为条件的学生分数
			③ 获取其中的最低分数
	——select min(score)		##②
			from student
			where tech_id=(
			      select tech_id			##①
			      from student as s
			      inner join teacher as t
			      on s.tech_id=t.id
			      where tech_id is not null
			      group by tech_id
			      order by max(score)
			      limit 1
			)
	#案例14:查询平均分数最高的指导组的 老师的详细信息
	——select *
			from teacher
			where id=(
			      select tech_id
			      from student as s
			      inner join teacher as t
			      on s.tech_id=t.id
			      group by s.tech_id
			      order by avg(score) desc
			      limit 1
			);
				
  1. 分页查询
    应用场景:当腰显示的数据,一页显示不完,需要分页提交SQL 请求
    语法:
    select 查询列表
    from 表
    【join type join 表2】
    on 连接条件
    where 筛选条件
    group by 分组字段
    having 分组后的筛选
    order by 排序字段
    limit offset, size;
    ——offset 要显示条目的起始索引(起始索引从0开始)
    ——size 要显示的条目个数(就是每个分页的条数)
语法:
		select 查询列表
		from 表
		【join type join 表2】
		on 连接条件
		where 筛选条件
		group by 分组字段
		having 分组后的筛选
		order by 排序字段
		limit offset, size;
	——offset 要显示条目的起始索引(起始索引从0开始)
	——size 要显示的条目个数(就是每个分页的条数)

特点:
		① limit 语句放在查询语句的最后
		② 公式
			要显示的页数 page,每页的条目数size
			select 查询列表
			from 表
			limit (page-1)*size, size;

#案例1:查询前五条学生信息
——select s.*
		from student as s
		limit 0, 5;
#案例2:查询第11~22 条学生信息
——select s.*
		from student as s
		limit 10, 12;
#案例3:有指导组的学生信息,并且分数较高的前15 名显示出来
——select s.*
		from student as s
		where tech_id is not null
		order by score desc
		limit 0, 15;

练习题:
已知表 stu_info
id	学号
name	姓名
email	邮箱		[email protected]
gradeId	年级编号
sex	性别(男、女)
age	年龄

已知表 grade
id		年级编号
gradeName		年级名称

	#案例1:查询所有学员的邮箱的用户名(注:邮箱中 @前面的字符即为用户名)
	——select substr(email, 1, instr(email, '@')-1) as 用户名
			from stu_info;
	#案例2:查询男生和女生的个数
	——select count(*) as 个数, sex
			from stu_info
			group by sex;
	#案例3:查询年龄>18 的所有学生的姓名和年级名称
	——select name as 姓名, gradeName as 年级名称
			from stu_info as s
			inner join grade as g
			on s.gradeId=g.id
			where s.age>18;
	#案例4:查询哪个年级最小年龄>20岁
	——select gradeName as 年级名称, min(age) as 最小年龄
			from stu_info as s
			left outer grade as g
			on s.gradeId=g.id
			group by g.id
			having 最小年龄>20;
	#案例5:试说出查询语句中涉及到的所有关键字,以及执行先后顺序
	——select 查询列表									⑦
			from 表1												①
			连接类型 join 表2								②
			on 连接条件											③
			where 筛选条件									④
			group by 分组列表								⑤
			having 分组后的筛选							⑥
			order by 排序列表								⑧
			limit 偏移, 条目数;								⑨
  1. 练习题
#案例1:查询每个专业的学生人数
——select count(*) as 学生人数, (select majorname from major as m where m.majorid= s.majorid) as 专业名称
		from stu_info as s
		group by majorid
#案例2:查询参加考试的学生中,每个学生的平均分、最高分
——select avg(score) as 平均分, max(score) as 最高分
		from result
		group by studentno
#案例3:查询姓‘张’的每个学生的最低分>60 的学号、姓名
		① 查询姓张的每个学生的成绩
		② 在① 的基础上进行result 按学号分组的查询
——select min(score) as 最低分数
		from result
		where studentno in(
		  select studentno as 学号
		  from stu_info
		  where studentname like '张%'
		)
		group by studentno
		having 最低分数>60;
#案例4:查询每个专业生日在‘1998-04-23’后的学生名、专业名称
		① 查询生日在‘1998-04-23’后的学生名字和专业编号
		② 查询所有专业的名称和编号
		③ ① + ② 建立内连接
——select studentname as 学生名字, m.majorname as 专业名称
		from stu_info as s
		inner join major as m
		on s.majorid=m.majorid
		where datediff(borndate,'1998-04-23')>0
		group by s.majorid
#案例5:查询每个专业的男生人数和女生人数分别是多少
		① 查询每个专业的人数和专业编号
		② 查询这个专业女男比例
——select majorid as 专业编号,
		(select count(*) from stu_info as at where sex='女' and s.majorid=at.majorid) as 女生人数,
		(select count(*) from stu_info as st where sex='男' and s.majorid=st.majorid) as 男生人数
		from stu_info as s
		group by majorid;
#案例6:查询专业和名字为‘张翠山’一样的学生的最低分
		① 查询名字为‘张翠山’的专业编号
		② 在① 的基础上查询该专业的学生编号
		③ 在 ② 的基础上查询这批学生的最低分数
——select min(score)
		from result
		where studentno in(
			 select studentno
			 from stu_info
			 where majorid in(
			   	select majorid from stu_info where studentname='张翠山'
			 )
		);
#案例7:查询大于60分的学生姓名、密码、专业名
		① 内连接stu_info 表和 result 表查询分数大于60的学生信息
		② 在① 的基础上内连接major 表
		③ 在② 的基础上查询学生姓名、密码、专业名
——select studentname as 学生名字, loginpwd as 密码, majorname as 专业名称
		from stu_info as s
		inner join result as r
		on r.studentno=s.studentno
		inner join major as m
		on s.majorid=m.majorid
		where score>60
#案例8:按邮箱位数分组,查询每组的学生个数
——select count(*) as 学生个数, length(email) as 邮箱长度
		from stu_info
		where email is not null
		group by length(email);
#案例9:查询学生名、专业名、分数
——select s.studentname as 学生名字, m.majorname as 专业名称, r.score as 分数
		from stu_info as s
		inner join result as r
		on s.studentno=r.studentno
		inner join major as m
		on s.majorid=m.majorid
#案例10:查询哪个专业没有学生,分别用左连接和有连接实现
——select count(*) as 学生人数, m.majorname as 专业名称
		from stu_info as s
		left outer join major as m
		on s.majorid=m.majorid
		group by m.majorid
		having count(*) is null
——select count(*) as 学生人数, m.majorname as 专业名称
		from stu_info as s
		right outer join major as m
		on m.majorid=s.majorid
		group by m.majorid
		having count(*)=0
#案例11:查询没有成绩的学生人数
——select count(*) as 学生人数
		from stu_info as s
		left outer join result as r
		on s.studentno=r.studentno
		where r.score is null;
  1. 联合查询
    union 联合 合并:将多条查询语句的结果合并成一条结果
    语法:
    查询语句1
    union
    查询语句2
    union
    查询语句3

    应用场景:
    要查询的结果来自于多个表,且多个表没有直接的连接关系,但查询的信息一致时
    特点:
    ① 要求多条查询语句的查询列数是一致的
    ② 要求多条查询语句的查询的每一列的类型和顺序最好一致
    ③ union 关键字默认去重,如果使用union all 可以包含重复项

#案例1:查询部门编号>90或邮箱包含a的员工信息
—— select e.* from employees as e where email like ‘%a%’
union
select s.* from employees as s where department_id>90;

MySQL 的查询学习就到此结束了。接下来可以继续学习DML 语言(插入、修改、删除)

你可能感兴趣的:(MySQL)