(1-7-4) MySql 的高级查询
目录
0. 前置总结
1. 聚合函数
1.1 平均值(avg)
1.2 求和(sum)
1.3 求 max
1.4 求 min
1.5 count 函数
2. 分组查询
2.1 常规分组查询
2.2 逐级分组查询
2.3 对分组结果集再次做汇总计算(with rollup)
2.4 group_concat 函数
2.5 having子句
3. 连接查询
3.1 内连接
(1) 查询每名员工的 部门信息
(2) 查询每个员工的工号、 姓名、 部门名称、底薪、 职位、 工资等级
(3) 查询与 龙龙 相同部门的 员工都有谁?
(4) 查询底薪 超过公司平均底薪的 员工信息
(5) 查询 RESEARCH 部门的人数、最高底薪、最低底薪、平均底薪、平均工龄
(6)查询每种职业的 最高工资、 最低工资、平均工资、 最高工资等级和最低工资等级
(7) 查询每个底薪 超过 部门 平均底薪的员工信息
3.2 外连接
(1) 查询 每个员工(如果有些员工没有部门id,则不能查询出)的部门信息
(2)查询每个部门的 名称和 部门的人数
(3). (UNION)查询每个部门 的名称 + 部门的人数 ( 如果没有部门的员工,部门名称使用null代替 )
(4).查询每名员工的编号、 姓名、部门、 月薪、 工资等级、 工龄、 上司编号、上司姓名、 上司部门
(5)外连接的 on 与 where的区别
4 . 子查询
4.1 where 子查询 (不推荐使用)
4.2 from 子查询,只会执行一次, 所以查询效率高
4.3. select 子查询 (查询效率低)
4.4 多行子查询
(1)需求:通过子查询 查找 龙龙 和 阿七七 两人的同事
(2)(ALL)查询 比 龙龙 和 阿七七 底薪都高的 同事
(3)(ANY)查询 比 龙龙 或 阿七七 底薪都高的 同事
(4) (exists - 不推荐) 查询工资等级 是3级 或 4级 的员工信息
0. 前置总结
-
数据统计分析
- 聚合函数
- 分组查询
- HAVING 子句
- 多表连接查询
- 内连接
- 外连接
- 多表查询
- 子查询
- 单行 子查询
- 多行 子查询
- WHERE 子查询
- FROM 子查询
- SELECT 子查询
各种子句的执行顺序
1. 聚合函数
1.1 平均值(avg)
(1) 求公司员工的平均月收入
# (1) 求公司员工的平均月收入
select avg(sal + ifnull(comm,0))
from t_emp;
(2) 非数字(姓名)数据平均值的结果为 0
# (2) 非数字(姓名)数据平均值的结果为 0
select avg(ename) from t_emp;
1.2 求和(sum)
(1) 查询 10、20 部门员工的 薪资总和
# (1) 查询 10、20 部门员工的 薪资总和
select sum(sal) from t_emp
where deptno in(10, 20)
1.3 求 max
(1) 求部门30 中员工底薪最高的工资
# (1) 求部门30 中员工底薪最高的工资
select max(comm) from t_emp where deptno = 30;
(2) 查询员工名字最长是几个字符
# (2) 查询员工名字最长是几个字符
select max(length(ename)) from t_emp;
1.4 求 min
(1) 查询最小的员工编号
# (1) 查询最小的员工编号
select min(empno) from t_emp;
(2) 查询最早的员工的入职日期
# (2) 查询最早的员工的入职日期
select min(hiredate) from t_emp;
1.5 count 函数
(1) 查询员工表中的 行总数与有效底薪行总数
# (1) 查询员工表中的 行总数与有效底薪行总数
select count(*) , count(comm) from t_emp;
(2) 查询 部门10和30中 底薪超过1900 ,并且工龄超过15年的员工数
# (2) 查询 部门10和30中 底薪超过1900 ,并且工龄超过15年的员工数
select count(*) from t_emp
where deptno in(10, 30)
and sal >1900
and datediff(now(), hiredate)/ 365 >= 15;
2. 分组查询
2.1 常规分组查询
(1) 查询各部门的平均薪资
# 分组查询# base
select avg(sal) from t_emp; # 2073.214286
select round(avg(sal)) from t_emp; # 2073
select deptno from t_emp;# 查询各部门的品骏薪资
select deptno , round(avg(sal)) from t_emp group by deptno;
2.2 逐级分组查询
(1) 查询各部门 的 员工数量 + 平均底薪 + 最早入职日期
# (1) 查询各部门 的 员工数量 + 平均底薪 + 最早入职日期select deptno, count(*), avg(sal), min(hiredate)from t_empgroup by deptno;
(2) 查询各部门 中 每种职位的 人员数量 + 平均月薪 (顺序以部门编号升序排列)
# (2) 查询各部门 中 每种职位的 人员数量 + 平均月薪 # (顺序以部门编号升序排列)select deptno, job, count(*), avg(sal)from t_empgroup by deptno, joborder by deptno asc;
2.3 对分组结果集再次做汇总计算(with rollup)
# 3. 对分组结果集再次做汇总计算(with rollup)select deptno, avg(sal), sum(sal), max(sal), min(sal), count(*)from t_empgroup by deptnowith rollup
2.4 group_concat 函数
(1) 查询各部门内 底薪超过1800远的 人数 + 员工姓名 + 员工薪资
# (1) 查询各部门内 底薪超过1800远的 人数 + 员工姓名 + 员工薪资select deptno, GROUP_CONCAT(ename), group_concat(sal), count(*)from t_empwhere sal >= 1800group by deptno
2.5 having子句
(1) 查询部门 平均底薪 超过1920元的 部门编号
# (1) 查询部门 平均底薪 超过1920元的 部门编号# (1.1) where使用 聚合函数 会报错
-- select deptno
-- from t_emp
-- where avg(sal) >= 1920
-- group by deptno;# (1.2) 使用having 子句select deptno from t_empgroup by deptno having avg(sal) >= 1920;
(2) 查询各部门中 , 1981年以后入职的员工的数量 > 4 的部门编号(以部门编号降序排列)
# (2) 查询各部门中 , 1981年以后入职的员工的数量 > 4 的部门编号# (以部门编号降序排列)select deptnofrom t_empwhere hiredate >= "1981-01-01"group by deptno having count(*) >= 4ORDER BY deptno desc;
(3)having 子句的特殊用法 (group by 1)
# (5) having 子句的特殊用法 (group by 1)
# base
select deptno, count(*)
from t_emp
group by 1;
# 结合having
select deptno, count(*)
from t_emp
group by 1
having deptno in(10, 20);
3. 连接查询
3.1 内连接
(1) 查询每名员工的 部门信息
(1-1) 使用on
# (1-1) 使用on
select em.empno, em.ename, de.dname
from t_emp em
join t_dept de
on em.deptno = de.deptno;
(1-2) 使用where
select de.dname, em.empno, em.ename
from t_dept de
join t_emp em
where de.deptno = em.deptno;
(1-3) 将 join 改写为 ,
select em.empno, em.ename, de.dname
from t_emp em ,t_dept de
where em.deptno = de.deptno;
(2) 查询每个员工的工号、 姓名、 部门名称、底薪、 职位、 工资等级
# (2) 查询每个员工的工号、 姓名、 部门名称、底薪、 职位、 工资等级
select em.empno, em.ename, de.dname, em.sal, em.job, sa.grade
from t_emp em join t_dept de on em.deptno = de.deptno
join t_salgrade sa on em.sal between sa.losal and sa.hisal;
(3) 查询与 龙龙 相同部门的 员工都有谁?
(3-1) 使用子查询实现 - 不推荐 - 查询效率太慢
# (3) 查询与 龙龙 相同部门的 员工都有谁?
# (3-1) 使用子查询实现 - 不推荐 - 查询效率太慢
select ename
from t_emp
where deptno = (select deptno from t_emp where ename = "龙龙")
and ename != "龙龙";
(3-2) 使用同表 内连接实现
# (3-2) 使用同表 内连接实现
select em2.ename
from t_emp em1 join t_emp em2 on em1.deptno = em2.deptno
where em1.ename = "龙龙"
and em2.ename != "龙龙";
(4) 查询底薪 超过公司平均底薪的 员工信息
(4-1) 使用 子查询实现
(4-1) 使用 子查询实现
select empno, ename, sal
from t_emp
where sal > (select avg(sal) from t_emp);
(4-2) 同表连接 !!!错误写法
# (4-2) 同表连接 错误写法
-- select em1.empno, em1.ename, em1.sal
-- from t_emp em1 join t_emp em2 on em1.sal > avg(em2.sal);
(4-3) 创表内连接 实现
# (4-3) 创表内连接 实现
select em.empno, em.ename, em.sal
from t_emp em join (select avg(sal) as avgSal from t_emp) ts
on em.sal > ts.avgSal
(5) 查询 RESEARCH 部门的人数、最高底薪、最低底薪、平均底薪、平均工龄
select count(*), max(em.sal), min(em.sal), avg(em.sal), floor(avg(datediff(now(), em.hiredate)/365))
from t_emp em join t_dept de on em.deptno = de.deptno
where de.dname = "RESEARCH";
(6)查询每种职业的 最高工资、 最低工资、平均工资、 最高工资等级和最低工资等级
# 查询每种职业的 最高工资、 最低工资、平均工资、 最高工资等级和最低工资等级
select em.job, max(em.sal), min(em.sal), avg(em.sal), max(sa.grade), min(sa.grade)
from t_emp em join t_salgrade sa
where em.sal between sa.losal and sa.hisal
group by em.job
(7) 查询每个底薪 超过 部门 平均底薪的员工信息
# (7) 查询每个底薪 超过 部门 平均底薪的员工信息
# 先构建 以部门分组的员工 薪资表
select deptno, avg(sal)
from t_emp
group by deptno# 在连接表进行查询
select em.empno, em.ename, em.job, em.sal
from t_emp as em join (select deptno, avg(sal) as avg from t_emp group by deptno) av
where em.deptno = av.deptno and em.sal > av.avg;
3.2 外连接
(1) 查询 每个员工(如果有些员工没有部门id,则不能查询出)的部门信息
# 查询 每个员工(如果有些员工没有部门id,则不能查询出)的部门信息# base 对比内连接
select em.empno, em.ename, dname
from t_emp em join t_dept de
on em.deptno = de.deptno# 外左连接(left join)
select em.empno, em.ename, dname
from t_emp em left join t_dept de
on em.deptno = de.deptno# 右左连接(right join)
select em.empno, em.ename, dname
from t_dept de right join t_emp em
on em.deptno = de.deptno
(2)查询每个部门的 名称和 部门的人数
# 2 查询每个部门的 名称和 部门的人数
# 2.1 正确写法(left join 加 去空数统计)
select de.deptno, de.dname, count(em.deptno)
from t_dept de left join t_emp em
on de.deptno = em .deptno
group by deptno;# 2.2 错误写法 使用内连接实现
select de.deptno, de.dname, count(*)
from t_dept de join t_emp em
on de.deptno = em .deptno
group by deptno;# 2.3 错误写法 使用left join ,统计总数
select de.deptno, de.dname, count(*)
from t_dept de left join t_emp em
on de.deptno = em .deptno
group by deptno;# 2.3 错误写法 使用left join ,统计部门表的部门编号总数
select de.deptno, de.dname, count(de.deptno)
from t_dept de left join t_emp em
on de.deptno = em .deptno
group by deptno;
(3). (UNION)查询每个部门 的名称 + 部门的人数 ( 如果没有部门的员工,部门名称使用null代替 )
(3-1)(UNION)正确实现
# 3. (UNION)查询每个部门 的名称 + 部门的人数 ( 如果没有部门的员工,部门名称使用null代替 )
(select de.dname, count(em.deptno) as headCount, group_concat(em.ename)
from t_dept de left join t_emp em
on de.deptno = em. deptno
group by de.deptno)
UNION
(select de.dname, count(em.deptno) as headCount, group_concat(em.ename)
from t_dept de right join t_emp em
on de.deptno = em. deptno
group by de.deptno);
(3-2)错误写法(内连接实现,部门数少一,人数少一)
# 3.2 错误写法(内连接实现,部门数少一,人数少一)
select de.dname, count(de.deptno) as headCount, group_concat(em.ename)
from t_dept de join t_emp em
on de.deptno = em. deptno
group by de.deptno;
(3-3) 错误写法(外连接实现, OPERATIONS的人数应为0, 龙龙员工没有统计到)
# 3.3 错误写法(外连接实现, OPERATIONS的人数应为0, 龙龙员工没有统计到)
select de.dname, count(de.deptno) as headCount, group_concat(em.ename)
from t_dept de left join t_emp em
on de.deptno = em. deptno
group by de.deptno;
(3-4) 错误写法(外连接实现, 龙龙员工没有统计到)
# 3.4 错误写法(外连接实现, 龙龙员工没有统计到)
select de.dname, count(em.deptno) as headCount, group_concat(em.ename)
from t_dept de left join t_emp em
on de.deptno = em. deptno
group by de.deptno;
(3-5) 错误写法(外连接实现, 部门数少一)
# 3.5 错误写法(外连接实现, 部门数少一)
select de.dname, count(em.deptno) as headCount, group_concat(em.ename)
from t_dept de right join t_emp em
on de.deptno = em. deptno
group by de.deptno;
(4).查询每名员工的编号、 姓名、部门、 月薪、 工资等级、 工龄、 上司编号、上司姓名、 上司部门
(4-1)全用左连接实现
# 4-1 实现方式1
select em.empno, em.ename, em.deptno, de.dname as empDept,(ifnull(em.comm, 0) + em.sal) salary, sa.grade, floor(DATEDIFF(now(), em.hiredate)/ 365 )as workAge, em.mgr, em1.ename as leaderName, de1.dname as leaderDept
from t_emp em
left join t_dept de on em.deptno = de.deptno
left join t_salgrade sa on em.sal between sa.losal and sa.hisal
left join t_emp em1 on em.mgr = em1.empno
left join t_dept de1 on em1.deptno = de1.deptno
(4-2)使用左连接 加上 拼表实现
# 4-2 实现方式2
select em.empno, em.ename, em.deptno, de.dname as empDept,(ifnull(em.comm, 0) + em.sal) salary, sa.grade, floor(DATEDIFF(now(), em.hiredate)/ 365 )as workAge,mgr.ename as leaderName, mgr.dname as leaderDept
from t_emp em
left join t_dept de on em.deptno = de.deptno
left join t_salgrade sa on em.sal between sa.losal and sa.hisal
left join
(select em1.empno, em1.ename, de1.dname
from t_emp em1
left join t_dept de1
on em1.deptno = de1.deptno) mgr
on em.empno = mgr.empno
(5)外连接的 on 与 where的区别
(5-1) 查询 20 部门的员工信息( 外连接实现 - 错误实现 )
# 5.1 查询 20 部门的员工信息( 外连接实现 - 错误实现 )
select em.empno, em.ename, de.dname
from t_emp em
left join t_dept de on em.deptno = de.deptno
and em.deptno = 20
(5-2) 查询 20 部门的员工信息( 外连接实现 +——where - 正确实现 )
# 5.2 查询 20 部门的员工信息( 外连接实现 +——where - 正确实现 )
select em.empno, em.ename, de.dname
from t_emp em
left join t_dept de on em.deptno = de.deptno
where em.deptno = 20
(5-3) 查询 20 部门的员工信息( 内连接实现 正确实现 )
# 5.3 查询 20 部门的员工信息( 内连接实现 正确实现 )
select em.empno, em.ename, de.dname
from t_emp em
join t_dept de on em.deptno = de.deptno
and em.deptno = 20;
4 . 子查询
4.1 where 子查询 (不推荐使用)
# 1. where 子查询 (不推荐,执行效率低)
# 查询底薪超过公司平均底薪的 员工信息
select empno, ename, sal
from t_emp
where sal >
(
select avg(sal)
from t_emp
);
4.2 from 子查询,只会执行一次, 所以查询效率高
# 2. from 子查询 只会执行一次, 所以查询效率高
select empno, ename, sal
from t_emp em
join
(
select avg(sal) as avgSal
from t_emp
) av
on em.sal > avgSal;
4.3. select 子查询 (查询效率低)
# 3. select 子查询 (查询效率低)
# 查询员工 的编号、 姓名、 部门编号
select empno, ename,
(
select dname
from t_dept
where deptno = em.deptno
)
from t_emp em
4.4 多行子查询
(1)需求:通过子查询 查找 龙龙 和 阿七七 两人的同事
# 4 多行子查询
# 单行子查询结果集 只有一条记录
# 多行子查询只能出现 where子句 和 from子句 中
# 需求:通过子查询 查找 龙龙 和 阿七七 两人的同事
select em1.empno, em1.ename
from t_emp em1
where
em1.deptno in
(
select em2.deptno
from t_emp em2
where em2.ename in ("龙龙", "阿七七")
)
and em1.ename not in ("龙龙", "阿七七");
(2)(ALL)查询 比 龙龙 和 阿七七 底薪都高的 同事
# 4.2 (ALL)查询 比 龙龙 和 阿七七 底薪都高的 同事
select em2.empno, em2.ename, em2.sal
from t_emp em2
where em2.sal > all
(
select em1.sal
from t_emp em1
where em1.ename in ("龙龙", "阿七七")
)
and em2.ename not in ("龙龙", "阿七七");
(3)(ANY)查询 比 龙龙 或 阿七七 底薪都高的 同事
# 4.3 (ANY)查询 比 龙龙 或 阿七七 底薪都高的 同事
select em2.empno, em2.ename, em2.sal
from t_emp em2
where em2.sal > any
(
select em1.sal
from t_emp em1
where em1.ename in ("龙龙", "阿七七")
)
and em2.ename not in ("龙龙", "阿七七");
(4) (exists - 不推荐) 查询工资等级 是3级 或 4级 的员工信息
# 4.4 (exists - 不推荐) 查询工资等级 是3级 或 4级 的员工信息
select empno, ename, sal
from t_emp
where exists(
select * from t_salgrade
where sal between losal and hisal
and grade in (3, 4)
);