问题描述
这是我在互联网上查找“相关子查询”时最常见的示例:
SELECT employee_number,name
FROM employees emp
WHERE salary > (
SELECT AVG(salary)
FROM employees
WHERE department = emp.department)
但我的问题是:在这个语法中,(以及其他类似的相关子查询)这是子查询最后一行的“函数” -> WHERE department = emp.department)
?
我的意思是,当执行这一行时,MysqL 会做什么?我不清楚这种语法背后的逻辑。
我试图只执行子查询,以便查看/理解给出的输出是什么,但它给了我错误。如何理解内部查询的输出?
我的目标是清楚地理解这个语法背后的逻辑,以便我能够理解何时使用它。如果它太复杂,是否有某种规则可以理解何时使用它?在哪个问题前面你说:“好吧,我必须使用相关子查询(用我的例子的语法)”?
解决方法
首先,让我们重写查询以对所有表使用别名并限定所有列。事情会变得更加清晰:
SELECT e1.employee_number,e1.name
FROM employees e1
WHERE e1.salary > (SELECT avg(e2.salary)
FROM employees e2
WHERE e2.department = e1.department);
(我建议你养成这样的习惯。要么使用别名并限定所有内容,要么什么都不做。两者的混合只是一团糟。)
现在回答您的问题:
要使子查询相关,它需要以某种方式“连接”到外部查询,否则就不相关。这就是子查询中的 WHERE
子句所做的。
如您所见,我们在整个查询中得到了 employees
的两个实例,别名为 e1
和 e2
。 (如果你有一个使用两个不同表的例子,它可能更容易理解......)
对于 e1
的每一行,子查询从 salary
获取平均 e2
,其中 e2
的行与当前处理的行具有相同的 department
来自e2
。 (至少这是逻辑上发生的事情——物理上执行的内容可能会在这里和那里采取一些捷径,但这对于理解含义并不重要查询。)然后将共享 salary
的平均值 department
与 salary
行的 e1
与 >
进行比较。
子查询不能单独执行,因为它是相关的。因此,如果您将它从整个查询的上下文中取出,就没有可比较的 department
,因为不再有其他实例 e1
。因此它失败了。
查询描述的是结果集,而不是执行计划——优化器会计算出来。
您的查询是相关子查询。第一件事是限定所有列引用,以便真正清楚哪些列是哪些:
SELECT e.employee_number,e.name
FROM employees e
WHERE e.salary > (SELECT AVG(e2.salary)
FROM employees e2
WHERE e2.department = e.department
------------------------^ correlation clause
);
这是在做什么?从概念上讲,引擎循环遍历 employees
表的每一行。对于每一行,它然后将薪水与同一部门中所有薪水的平均值进行比较——这就是相关性子句的作用。
这描述了产生的结果集。实际的执行计划可能与上面描述的有所不同。