分组查询&并集查询&关联查询&子查询

120 阅读6分钟

分组查询:

关键字:group by 分组

分组概念:就按照一定的规则,将一个数据集划分为若干个小的区域

然后针对每个小的区域做汇总处理

简单说就是根据某个字段进行分组(相同的放一组,不同的分到不同的分组)

注意:

使用group by的时候,select子句中只能有group by子句中的字段,或者被聚合函数包裹的字段

group by后面如果要加条件,必须用having进行连接

-- 查看每个部门的平均工资是多少???  round() 四舍五入
select round(avg(sal+ifnull(comm,0)),2),deptno from emp group by deptno;
select round(123.6); -- 124
select round(123.156,2); -- 123.16
-- 类似于去重效果
select distinct deptno from emp;
select deptno from emp group by deptno;
-- 查询除了salesman职业以外的其他各个职业的工资总和是多少?
-- 先找出所有职业的工资总和,然后再排除salesman
select job,sum(sal+ifnull(comm,0)) from emp group by job;
select job,sum(sal+ifnull(comm,0)) from emp group by job where job != 'salesman';  -- 报错
select job,sum(sal+ifnull(comm,0)) from emp group by job having job != 'salesman'; -- 正确
select job,sum(sal+ifnull(comm,0)) from emp where job != 'salesman' group by job;  -- 不能这么写,某些场景下会报错

where 和 having的区别

where是在结果返回之前起作用,where的优先级要高于group by

having 是结果返回之后起作用

where是从数据表中字段直接进行筛选

having是从select子句中进行筛选

-- where 和 having 都可以使用的场景
select ename,deptno from emp where deptno = 20;
select ename,deptno from emp having deptno = 20;

-- where可用,having不可用
select ename from emp where deptno = 20;  -- 表中有deptno字段  不报错
select ename from emp having deptno = 20; -- select子句中没有deptno这个字段,所以报错
-- where不可用,having可用
select job,sum(sal+ifnull(comm,0)) from emp group by job where job != 'salesman';  -- 报错
select job,sum(sal+ifnull(comm,0)) from emp group by job having job != 'salesman'; -- 正确

select job,sum(sal+ifnull(comm,0)) from emp where job != 'salesman' group by job;  -- 不能这么写,某些场景下会报错
select job,sum(sal+ifnull(comm,0))as temp from emp where temp>200 group by job;  -- 不能这么写,表中没有temp这个字段,所以报错

逐级分组:

group by 子句用可以有多个字段

-- 查询每个部门里面,每种职位的员工的数量和平均工资?
select deptno,job,count(1),avg(sal+ifnull(comm,0)) from emp group by deptno,job;

group_concat() 很重要,很多场景需要使用到这个库函数

作用:将group by查询出来的同一个分组中的值,拼接起来,返回一个字符串结果

举例场景:

博客系统

文章 和 标签

一篇文章可以对应N个标签

-- 查看每个职业下面有多少员工,需要看到员工的名字
select group_concat(ename),job from emp group by job;
-- concat() 用于字符串拼接
select concat(1,2); -- 12
select concat(null,1); -- null
select concat(-1,1); -- -11

并集查询

将N个查询语句的结果集 合并到一起

关键字:union :不会去重

union all:会去除重复数据

-- 查询底薪在 1200 以上的员工信息
select * from emp where sal > 1200;
-- 查询底薪在 2600 以上的员工的信息
select * from emp where sal > 2600;
-- 合并两个结果集在一起
select * from emp where sal > 1200
union 
select * from emp where sal > 2600;
-- 合并两个结果集在一起 union all不会去除重复数据
select * from emp where sal > 1200
union all
select * from emp where sal > 2600;
-- 使用union的时候,select子句的字段数量和类型要相同
select comm,sal from emp where sal > 1200
union all
select sal,comm from emp where sal > 2600;

关联查询:

概念:就是从多张表中联合查询数据,结果集来源于多张不同的表。

在关联查询中,用于指定表和表之间的联系条件:关联条件

注意:

  1. 关联查询中,一定要有关联条件,否则会出现笛卡尔积(n*n 没有意义,开销巨大)

  2. N张表关联,至少要有N-1个关联条件。

  3. 关联条件和过滤条件要同时成立

-- 查询所有员工所在部门的地址?
select ename,loc from emp,dept where emp.deptno = dept.deptno;
select ename,loc from emp e,dept d where e.deptno = d.deptno;
-- 查看在 DALLAS 工作的员工有哪些?
select ename,loc from emp e,dept d where e.deptno = d.deptno and d.loc = 'DALLAS';
-- 查看底薪高于2000的员工的名字,底薪,所在部门的名字?
-- 先把要查的字段写上,再看这些字段来源于几张表,然后把表名写上,然后再看表的关联条件,再写过滤条件
select ename,sal,dname from emp e,dept d where e.deptno = d.deptno and e.sal > 2000;

join关联

全连接 inner join 返回的两张表的交集(几乎不用,因为有简写)

左外连接 left outer join 左表数据全部返回,右表返回有关联的数据

右外连接 right outer join 右表的数据全部返回,左边返回右关联的数据

join优化:

  1. 小的结果集去驱动大的结果集,就是用数据量小的表去驱动大的表,可以减少循环的个数,也就是扫描的个数

  2. 用来Join的字段要加上索引,会自动触发INLJ的算法

  3. 如果无法使用索引,可以调整join buffer的大小

  4. 减少不必要的字段查询(就是不要用*)

-- 查看在dalllas工作的员工有哪些
select ename,loc from emp e,dept d where e.deptno = d.deptno and d.loc = 'DALLAS';
-- 把两个表之间的,替换成inner join 把where 替换成On
select ename,loc from emp e inner join dept d on e.deptno = d.deptno and d.loc = 'DALLAS';
-- inner可以省略
select ename,loc from emp e join dept d on e.deptno = d.deptno and d.loc = 'DALLAS';

--  左外连接    left outer join 左表数据全部返回,右表返回有关联的数据
select e.*,d.* from emp e left outer join dept d on e.deptno = d.deptno;
-- outer一般都不写,可以省略
select e.*,d.* from emp e left join dept d on e.deptno = d.deptno;

子查询:(不到万不得已,少用)

子查询是一条sql语句,是嵌套在其他sql中的

作用是为外层sql语句提供结果集

-- 查询和FORD同部门的员工都有谁?
-- 拆开来查,然后再组合到一起
-- 1. 查看FORD的部门号是多少
select deptno from emp e where e.ename = 'FORD';  -- 20
-- 2. 查看20号部门的员工都有谁
select * from emp e where e.deptno = 20;
-- 3. 组合到一起
select * from emp e where e.deptno =(select deptno from emp e where e.ename = 'FORD');
-- 查看比公司平均工资高的员工都有谁?
select * from emp e where e.sal > (select avg(sal) from emp);
-- 查看职位和 SMITH 相同,但是薪水比 FORD 低的员工都有谁?
select job from emp e where e.ename = "smith"; 
select sal from emp e where e.ename = 'ford';
select * from emp e where e.job = (select job from emp e where e.ename = "smith") 
and sal<(select sal from emp e where e.ename = 'ford');
-- 子查询用在ddl中  通常用于表的快速备份
create table t_emp as (select * from emp);
create table emp as (select * from t_emp);
-- 子查询用在dml中  
insert into t_emp(empno,ename) select 1,"Andy";
insert into t_emp(empno,ename) select empno,ename from emp;