在子查询中引用父查询

Referencing Parent query inside Child query

当子查询引用父查询时,任何人都可以解释这个查询。 SQL如何看待这个

员工的第二高薪水:

select max(e1.sal),e1.deptno 
from s_emp e1 
where sal < (select max(sal) from s_emp e2 where e2.deptno = e1.deptno) 
group by e1.deptno;

我测试了它并且有效。

首先删除 group by 和聚合并考虑这个查询:

select e1.sal, e1.deptno 
from s_emp e1 
where e1.sal < (select max(sal) from s_emp e2 where e2.deptno = e1.deptno)

它 returns table 的所有行,除了 deptno 中最大 sal 的行。
为什么?
因为每一行的 sal 都与 deptno 的最高薪水进行比较,并且必须小于。
WHERE 子句中的子查询对 table:

的每一行执行一次
select max(e2.sal) from s_emp e2 where e2.deptno = e1.deptno

并且对于每一行,它 returns 当前行的最大值 sal deptno
所以结果是所有小于当前行的 deptno.
的最大值 salsal 现在,如果您添加 group by deptno 和聚合,您将获得每个 deptno 返回行的最大值 sal,即 2nd 最高 sal 对于每个 deptno,因为所有排名靠前的都已被排除。

这称为相关子查询,因为子查询的结果对于外部查询的每一行都可能不同。

当 MySQL 运行 是一个查询时,您可以将其视为对集合的 foreach 循环。例如在 PHP 语法中:

foreach (s_emp as e1) {
  ...
}

必须 运行 外部查询的每一行的子查询,然后才能评估 < 比较。随着行数的增加,这将变得非常昂贵。如果 table 有 N 行,它将 运行 子查询 N 次,即使 deptno! 只有几个不同的值也是如此。 MySQL 不够聪明,无法记住 运行 相同 deptno 值的子查询后的结果。

相反,您可以通过这种方式获得结果,它将计算所有 deptnos 的 max(sal),并将这些结果保存在临时 table。

select max(e1.sal), e1.deptno
from s_emp e1
join (select deptno, max(sal) as max_sal from s_emp group by deptno) as e2
  on e1.deptno = e2.deptno
where e1.sal < e2.max_sal
group by e1.deptno

这个查询的目的似乎是 return 每个部门第二高的薪水,对吧?

这是另一个使用 MySQL 8.0 中的 window 函数的解决方案:

select deptno, sal
from (
  select deptno, sal, dense_rank() over (partition by deptno order by sal desc) as dr
  from s_emp
) as e1
where dr = 2