与NOT EXISTS和子查询混淆

时间:2015-05-17 16:52:30

标签: mysql sql database

我很难理解NOT EXISTS和子查询的组合是如何工作的。

我理解通过添加NOT EXISTS,查询将返回子查询不会返回的所有行。在以下情况下我们使用它时,我不明白它是如何工作的。

+-------------+--------+
| id_employee | salary |
+-------------+--------+
| E001        |   1000 |
| E002        |   1001 |
| E003        |    999 |
| E004        |   1001 |
+-------------+--------+

并尝试以下查询:

SELECT E.id_employee, E.salary
FROM Employees E
WHERE NOT EXISTS (
    SELECT F.id_employee
    FROM Employees F
    WHERE F.salary > E.salary
);

返回:

+-------------+--------+
| id_employee | salary |
+-------------+--------+
| E002        |   1001 |
| E004        |   1001 |
+-------------+--------+

好吧,我真的无法理解F.salary > E.salary比较是如何工作的,因为如果它逐行比较两个表(它们是相同的),那么它们是否有意义我要退回任何一行。

你能否给我一些关于它是如何工作的暗示?

3 个答案:

答案 0 :(得分:1)

NOT EXISTS通常与Correlated Subquery一起使用,即Outer和Inner查询之间存在关系(如果没有“table not found”错误,则无法自行运行子查询代码)。你的例子是相关的,但是很奇怪。

逻辑上它的处理方式如下:

对于employee表中的每一行,运行以下查询:

SELECT F.id_employee
FROM Employees F
WHERE F.salary > <salary of the current row>

如果此查询未返回任何行(即,没有薪水大于当前行的行),则NOT EXISTS计算结果为true并从employee表中返回此行。

实际上,此查询返回薪水最低的行。

相关EXISTSJOIN非常相似,而NOT EXISTS是一种反JOIN,只返回那些无法连接的行。这是常见用法,查找第二个表中不存在的值的行,例如查找具有无效/不存在的部门编号的员工

SELECT *
FROM Employees E
WHERE NOT EXISTS (
    SELECT *
    FROM Departments D
    WHERE E.department_number = D.department_number
);

答案 1 :(得分:0)

由于您在子查询中没有指定其他条件而不是:

 F.salary > E.salary

你从E获得任何一行,其中F中没有其他条目的薪水高于它。由于E002E004的薪水均为1001,而其他任何人的工资都不超过1001E002E004归还。

如果您将WHERE更改为:

F.salary >= E.salary

由于每个人的薪水都低于或等于另一名员工的薪水,您将无法获得任何记录。

答案 2 :(得分:0)

好的,每行都会计算WHERE子句。 WHERE子句将仅返回谓词求值为TRUE的行。你的谓词是

NOT EXISTS (
    SELECT F.id_employee
    FROM Employees F
    WHERE F.salary > E.salary
);

因此,结果集将仅包含将此谓词计算为TRUE的行。对于工资为1000的第1行,存在工资较大的行,因此对于此行,谓词为FALSE,并从结果集中删除。第二行薪水是1001,并且没有其他行的薪水更高,因此对于此行,谓词的计算结果为TRUE,此行将位于结果集中。

相关问题