SQL基础系列(五)——子查询

子查询是在一个完整的查询语句中,嵌套不同功能的小查询,从而完成复杂查询的一种编写形式。本部分主要介绍非关联子查询,关联子查询的适用场景,语句写法,执行逻辑及相对应的注意事项。

目录

1.非关联子查询

1.1执行逻辑

1.2在WHERE子句中使用子查询

1.2.1子查询返回一个具体数据

1.2.2子查询返回一条数据

1.2.3子查询返回多行单列数据

1.3在HAVING子句中使用子查询

1.4在FROM子句中使用子查询

2.关联子查询

2.1在细分的组内进行比较

2.2使用EXISTS,NOT EXISTS时使用关联子查询


1.非关联子查询

在SELECT子句、GROUP BY子句、HAVING子句、ORDER BY子句中均可使用子查询语句,较常用的是WHERE子句、HAVING子句和FROM子句。

1.1执行逻辑

在非关联子查询中,子查询语句可以独立执行,查询结果是一个数据,一条数据,或者一张临时数据表,主查询可使用子查询结果进行操作。

1.2在WHERE子句中使用子查询

在WHERE子句中,通常使用子查询结果作为筛选条件。

1.2.1子查询返回一个具体数据

题目1:求table表中工资高于平均工资的数据。

在WHERE子句中不可以使用函数,因此想要求大于某个统计值的数据,不能使用如下写法:

🙅SELECT * FROM table WHERE salary>avg(salary);

正确的示例如下:

🙆SELECT * FROM table WHERE salary>(SELECT avg(salary) FROM table);

在上面标红的子查询语句中,返回结果是一个平均值,主查询语句在执行时判断平均工资是否大于平均值,符合条件则作为查询结果展示。

题目2:求table1表中和'ELLEN'职位一样的数据

思路同上,使用子查询语句求出'ELLEN'的职位,再将其作为筛选条件,判断职位与其一致的数据。

🙆SELECT * FROM table1

      WHERE job=(SELECT job FROM table1 WHERE name='ELLEN');

注释:

  • 在WHERE子句中可使用多个子查询,支持多个条件中分别使用子查询语句;
  • 子查询语句可以进行嵌套; 

1.2.2子查询返回一条数据

子查询返回一条数据,即多个属性,使用多个属性值进行数据判断,示例如下:

 题目1:求table表中与'ELLEN'工作及工资均一致的数据。

题目解析:先找出'ELLEN'的工作及工资,然后判断数据中同时和这两个属性一致的数据。

🙆SELECT * FROM table1

      WHERE (job,salary)=(SELECT job,salary FROM table1 WHERE name='ELLEN');

语句返回的结果中包含ELLEN及与其工作和工资一致的数据。

1.2.3子查询返回多行单列数据

此种情况下,子查询返回多数据时一个数据的范围,在WHERE子句中通过数据范围进行筛选时,需用操作符IN、ANY、ALL

(1)IN

题目1:求每个部门最低工资,并查找出与最低工资相同的员工信息

🙆SELECT * FROM table1

      WHERE sal IN (SELECT min(sal) FROM table1 GROUP BY deptno);

子查询中返回的是每个部门的最低工资,一列多行。根据子查询的结果,判断工资在子查询数据范围内的数据。

⚠️:IN,或者NOT IN 后的数据范围内存在值为NULL的数据,则查询结果为空。

(2)ANY

题目1:求每个部门最低工资,并查找出大于任意一个部门最低工资的员工信息

🙆SELECT * FROM table1

      WHERE sal >ANY (SELECT min(sal) FROM table1 GROUP BY deptno);

>ANY:大于其后数据范围内最小值

<ANY:小于其后数据范围内最大值

=ANY:效果相当于IN

<>ANY:🙅错误用法 

(3)ALL

题目1:求每个部门最低工资,并查找出比所有部门最低工资都大的员工信息

🙆SELECT * FROM table1

      WHERE sal >ALL (SELECT min(sal) FROM table1 GROUP BY deptno);

<>ALL:相当于NOT IN

>ALL:大于其后数据范围内的最大值

<ALL:小于其后数据范围内的最小值

=ALL:🙅错误用法

1.3在HAVING子句中使用子查询

在HAVING子句中使用子查询,即对分组进行过滤,子查询往往返回的都是一个具体的数据(单行单列)。

题目:筛选出平均工资大于全体员工平均工资的部门

🙆SELECT deptno, avg(sal) FROM table1

      GROUP BY deptno

      HAVING avg(sal)> (SELECT avg(sal) FROM table1);

⚠️:分组语句中,SELECT后只能跟分组字段、函数及常数,不能使用非分组函数;

解析思路:

HAVING子句中限定组的筛选条件。题目中,需计算出各部门的平均工资,并筛选出符合条件的部门(部门就是分组标准)。

子查询语句中,计算出部门整体的平均工资,然后将各部门的平均工资与之对比。

1.4在FROM子句中使用子查询

FROM子句限定查询的数据表,使用子查询,即将子查询的结果作为一张临时的数据表使用。

题目:emp表:部门编号(deptno),姓名(name),工资(sal),职位(job),雇佣日期(hiredate)

筛选出公司每个员工的编号,姓名,工资,职位,雇佣日期,部门最大工资,部门最小工资

题目分析:

要求的取值结果中,包含分组统计的内容(部门最大最小值)及数据表其他字段。

分组情况下,SELECT子句仅可跟分组字段,函数,常量。题目需要展示非分组字段。

因此,需要把分组统计的结果单独查询出作为一个数据表,将此表与原表进行联结。

SELECT e.deptno,e.name,e.sal,e.job,e.hiredate,t.max,t.min

FROM emp e,

           (SELECT deptno,max(sal) max,min(sal) min FROM emp GROUP BY deptno) t

WHERE e.deptno=t.deptno;

2.关联子查询

关联子查询:子查询不可独立执行,子查询中使用主查询的列作为条件。先执行外部查询,将外部查询出的每条数据传递给子查询语句执行,子查询执行一次返回执行结果后,主查询根据子查询结果进行决策。

2.1在细分的组内进行比较

题目1:根据各个部门的平均工资,查询超过本部门平均工资的员工信息。

🙅错误写法

🙅SELECT * FROM table1

      WHERE sal >(SELECT avg(sal) FROM table1 GROUP BY deptno);

错误原因:在子查询中查每个部门的平均工资,但是是多行多列的结果。WHERE条件后,当子查询结果为单行单列时,才能进行正常比较。

🙆正确写法

🙆SELECT * FROM table1 t1

      WHERE sal >(SELECT avg(sal) FROM table1 t2 WHERE t1.deptno=t2.deptno);

上面子查询的语句为关联子查询,子查询的where子句中使用了主查询的字段列作为限定条件。

在执行这条语句时,取出主查询中的一条员工数据,传入子查询中,在子查询中筛选此员工同部门的数据,计算部门的平均工资。主查询中将此员工工资和同部门的平均工资对比,符合条件则保留员工数据。然后再取下一个员工,重复执行以上过程。

2.2使用EXISTS,NOT EXISTS时使用关联子查询

题目:用户表customer 订单表order 

求没有下过订单的客户的信息

🙆SELECT * FROM customer c

      WHERE not exists 

                     (SELECT customer_id FROM order o WHERE c.customer_id=o.customer_id);

假设张三下了订单,李四没有下订单。

那么在语句执行的时候,通过外查询语句取张三的信息,通过子查询中的WHERE判断,子查询可取出一条数据,不符合not exists,此条数据不保留。

取李四的数据,通过子查询中的where判断,子查询无符合条件的数据,符合not exists,此条数据保留。

EXISTS,NOT EXISTS还有更复杂的用法,后续可以单独介绍一下。看到一篇讲的比较详细的文章,大家如果有兴趣可以移步至:

EXISTS,NOT EXISTS


版权声明:本文为weixin_44077468原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>