MySQL数据库,子查询

子查询指一个查询语句嵌套在另一个查询语句内部的查询。很多时候查询需要从结果集中获取数据,或者需要从同一个表中先计算得出一个数据结果,然后与这个数据结果(可能是某个标量,也可能是某个集合)进行比较。

例:想查询工资比BLACK的工资高的员工的信息

SELECT ename , sal 
FROM emp
WHERE sal > (
			SELECT sal 
			FROM emp 
			WHERE ename = 'BLAKE'
            );

外部的查询称为外查询(或主查询),内部的查询称为内查询(或子查询)。

注:

  • 子查询在主查询之前执行完成。

  • 子查询的结果被主查询使用。

  • 子查询要包含在括号内

  • 将子查询放在比较条件的右侧(建议)。

  • 单行操作符对应单行子查询,多行操作符对应多行子查询

子查询的分类:

角度一:单行子查询、多行子查询

单行子查询返回一条记录,多行子查询返回多条记录。

角度二:相关子查询、不相关子查询(或关联子查询和不关联子查询)(即从内查询是否执行多次的角度)

  •  子查询从数据表中查询了数据结果,如果这个数据结果只执行一次,然后这个数据结果作为主查询的条件执行,那么这样的子查询称为不相关子查询。

  • 如果子查询需要执行多次,即采用循环的方式,先从外部查询开始,每次都传入子查询进行查询,然后再将结果反馈给外部,这种嵌套的执行方式就称为相关子查询。

单行子查询:

单行比较操作符:

注:

  • 子查询可以放在任何可以用“值”表示的位置。比如WHERE、HAVING里的表达式中,SELECT中的字段中,CASE表达式中等等。

  • 子查询只返回一个结果值,不会返回行

  • 子查询查询不到结果则返回NULL

  • 多行子查询的结果不能放在单行比较操作符后使用

例,在CASE表达式中使用单行子查询:

SELECT empno , ename , CASE deptno
WHEN (
      SELECT deptno
      FROM dept
      WHERE loc = 'NEW YORK'
     ) 
THEN 'AAA'
ELSE 'BBB'
END 'location' #别名
FROM emp;

多行子查询:

多行子查询也称为集合比较子查询,返回多行,使用多行比较操作符。

多行比较操作符:

注:

可以将多行子查询的结果当作一张表使用,但是,必须要给此表取别名

例如:

SELECT MIN(sal_avg)
FROM (
      SELECT AVG(sal) sal_avg
      FROM emp
      GROUP BY deptno
     ) das; -- das即为此表的别名。

多行子查询中的空值问题:

如果多行子查询的结果的其中一条中出现NULL,用NOT IN加此子查询的结果为空,因为NOT IN实际上会用<>来与每个结果比较,若结果中有空值那么 <>NULL的结果就是NULL,正确的做法应该是将多行子查询的结果中的NULL值过滤掉。

例:

SELECT ename
FROM emp
WHERE NOT IN (
              SELECT mgr
              FROM emp
              WHERE mgr IS NOT NULL
             );

相关子查询:

如果相关子查询的执行依赖于外部查询,通常情况下都是因为子查询中的表用到了外部的表,并进行了条件关联,因此每执行一次外部查询,子查询都要重写计算一次,这样的子查询就是关联子查询。

相关子查询按照一行接一行的顺序执行,主查询的每一行都执行一次子查询。

例,查询员工中工资大于本部门平均工资的员工的姓名、薪资、和部门号(使用相关子查询):

SELECT ename , sal , deptno
FROM emp e1
WHERE sal > (
             SELECT AVG(sal)
             FROM emp e2
             WHERE deptno = e1.deptno   #子查询要与主查询做相关联,即主查询中的每一行的执行都要重新执行一次子查询。
            );

在SELECT中除了GROUP BY和LIMIT之外,其他的位置都可以使用子查询。

EXISTS与NOT EXISTS

关联子查询通常也会和EXISTS操作符一起来使用,用来检查子查询中是否存在行。

每一行执行时:

如果在子查询的结果中不存在行,返回FALSE

如果在子查询的结果中存在行,返回TRUE

返回FALSE即主查询中的相应的行不会成为主查询的结果,返回TRUE即主查询中的相应的行会成为主查询的结果。

NOT EXISTS表示如果在子查询的结果中不存在行,则返回TRUE,否则返回FALSE(与EXISTS相反)。

EXISTS后的子查询并不会返回行,只会返回TRUE或FALSE。

例:

SELECT empno , ename , job , deptno
FROM emp e1
WHERE EXISTS (
              SELECT *
              FROM emp e2
              WHERE e1.empno = e2.mgr
              );

当员工是属于管理者时,主查询才会接收到子查询返回的TRUE。

相关子查询也可以使用到更新、删除操作中,称为相关更新、相关删除。

多层自查询的三种经典的查询方式:

例,查询公司中平均工资最高的工作职位:

方式一:

步骤:

①    先求各部门的平均工资

②    再到①中的数据中求出最高的平均工资

③    再根据②中的数据对应出最高的平均工资对应的工作职位

SELECT job
FROM emp
GROUP BY job
HAVING AVG(sal) = (
                   SELECT MAX(avg_sal)
                   FROM (
                         SELECT AVG(sal) avg_sal
                         FROM emp
                         GROUP BY job
                         ) avg_tab
                  );

方式二:

比起方式一,方式二直接 <= ALL的方式将求最大的平均工资的步骤隐藏在比较操作符中,减少了子查询的次数。

SELECT job
FROM emp
GROUP BY job
HAVING AVG(sal) >= ALL (
                        SELECT AVG(sal)
                        FROM emp
                        GROUP BY job    
                        );

方式三:

方式三使用的是先降序排列,再用分页LIMIT的方式,只取第一个记录,取得的即是最高的平均工资,也减少了子查询的次数。

SELECT job
FROM emp
GROUP BY job
HAVING AVG(sal) = (
                   SELECT AVG(sal) avg_sal
                   FROM emp
                   GROUP BY job
                   ORDER BY avg_sal DESC
                   LIMIT 0,1
                  );

  • 21
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二狗mao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值