我正在尝试学习SQL,并且很难理解EXISTS语句.我偶然发现了关于"存在"的引用并且不明白:
使用exists运算符,子查询可以返回零行,一行或多行,并且条件只检查子查询是否返回任何行.如果查看子查询的select子句,您将看到它包含一个文字(1); 由于包含查询中的条件只需要知道返回了多少行,因此子查询返回的实际数据无关紧要.
我不明白的是外部查询如何知道子查询检查哪一行?例如:
SELECT *
FROM suppliers
WHERE EXISTS (select *
from orders
where suppliers.supplier_id = orders.supplier_id);
Run Code Online (Sandbox Code Playgroud)
我知道如果供应商和订单表中的id匹配,则子查询将返回true,并且将输出供应商表中匹配行的所有列.我不知道的是,如果只返回true或false,子查询如何传达应该打印哪个特定行(假设具有供应商ID 25的行).
在我看来,外部查询和子查询之间没有关系.
soj*_*jin 87
想一想:
对于'each'行Suppliers
,检查表中是否存在Order
满足条件的行Suppliers.supplier_id
(这来自外查询当前'row')= Orders.supplier_id
.当你找到第一个匹配的行时,停在那里 - WHERE EXISTS
已经满足了.
外部查询和子查询之间的神奇链接在于,Supplier_id
从外部查询传递到每个已计算的行的子查询.
或者,换句话说,子查询是针对外部查询的每个表行执行的.
它不像子查询在整体上执行并获得'true/false',然后尝试将此'true/false'条件与外部查询匹配.
OMG*_*ies 31
在我看来,外部查询和子查询之间没有关系.
您认为EXISTS示例中的WHERE子句在做什么?当SUPPLIERS引用不在EXISTS条款中的FROM或JOIN子句中时,您如何得出这个结论?
EXISTS评估为TRUE/FALSE,并在标准的第一个匹配时退出为TRUE - 这就是为什么它可以更快IN
.还要注意,EXISTS中的SELECT子句被忽略 - IE:
SELECT s.*
FROM SUPPLIERS s
WHERE EXISTS (SELECT 1/0
FROM ORDERS o
WHERE o.supplier_id = s.supplier_id)
Run Code Online (Sandbox Code Playgroud)
......应该通过零误差击中除法,但不会.WHERE子句是EXISTS子句中最重要的部分.
另请注意,JOIN不是EXISTS的直接替代,因为如果有多个子记录与父级关联,则会有重复的父记录.
Ant*_*ull 22
您可以使用产生相同的结果JOIN
,EXISTS
,IN
,或INTERSECT
:
SELECT s.supplier_id
FROM suppliers s
INNER JOIN (SELECT DISTINCT o.supplier_id FROM orders o) o
ON o.supplier_id = s.supplier_id
SELECT s.supplier_id
FROM suppliers s
WHERE EXISTS (SELECT * FROM orders o WHERE o.supplier_id = s.supplier_id)
SELECT s.supplier_id
FROM suppliers s
WHERE s.supplier_id IN (SELECT o.supplier_id FROM orders o)
SELECT s.supplier_id
FROM suppliers s
INTERSECT
SELECT o.supplier_id
FROM orders o
Run Code Online (Sandbox Code Playgroud)
让\xe2\x80\x99s 假设我们的数据库中有以下两个表,它们形成一对多表关系。
\n\n该student
表是父表,是student_grade
子表,因为它有一个 Student_id 外键列引用学生表中的 id 主键列。
其中student table
包含以下两条记录:
| id | first_name | last_name | admission_score |\n|----|------------|-----------|-----------------|\n| 1 | Alice | Smith | 8.95 |\n| 2 | Bob | Johnson | 8.75 |\n
Run Code Online (Sandbox Code Playgroud)\n并且,该student_grade
表存储学生获得的成绩:
| id | class_name | grade | student_id |\n|----|------------|-------|------------|\n| 1 | Math | 10 | 1 |\n| 2 | Math | 9.5 | 1 |\n| 3 | Math | 9.75 | 1 |\n| 4 | Science | 9.5 | 1 |\n| 5 | Science | 9 | 1 |\n| 6 | Science | 9.25 | 1 |\n| 7 | Math | 8.5 | 2 |\n| 8 | Math | 9.5 | 2 |\n| 9 | Math | 9 | 2 |\n| 10 | Science | 10 | 2 |\n| 11 | Science | 9.4 | 2 |\n
Run Code Online (Sandbox Code Playgroud)\n假设\xe2\x80\x99s 表示我们想要获取数学课上获得 10 分的所有学生。
\n如果我们只对学生标识符感兴趣,那么我们可以运行如下查询:
\nSELECT\n student_grade.student_id\nFROM\n student_grade\nWHERE\n student_grade.grade = 10 AND\n student_grade.class_name = \'Math\'\nORDER BY\n student_grade.student_id\n
Run Code Online (Sandbox Code Playgroud)\n但是,应用程序有兴趣显示 a 的全名student
,而不仅仅是标识符,因此我们student
还需要表中的信息。
为了过滤student
数学成绩为 10 的记录,我们可以使用 EXISTS SQL 运算符,如下所示:
SELECT\n id, first_name, last_name\nFROM\n student\nWHERE EXISTS (\n SELECT 1\n FROM\n student_grade\n WHERE\n student_grade.student_id = student.id AND\n student_grade.grade = 10 AND\n student_grade.class_name = \'Math\'\n)\nORDER BY id\n
Run Code Online (Sandbox Code Playgroud)\n运行上面的查询时,我们可以看到仅选择了 Alice 行:
\n| id | first_name | last_name |\n|----|------------|-----------|\n| 1 | Alice | Smith |\n
Run Code Online (Sandbox Code Playgroud)\n外部查询选择student
我们感兴趣的行列返回给客户端。但是,WHERE 子句将 EXISTS 运算符与关联的内部子查询一起使用。
如果子查询至少返回一条记录,则 EXISTS 运算符返回 true;如果没有选择任何行,则 EXISTS 运算符返回 false。数据库引擎不必完全运行子查询。如果匹配单个记录,则 EXISTS 运算符返回 true,并选择关联的其他查询行。
\n内部子查询是相关的,因为表的 Student_id 列student_grade
与外部 Student 表的 id 列匹配。
如果你有一个where子句看起来像这样:
WHERE id in (25,26,27) -- and so on
Run Code Online (Sandbox Code Playgroud)
您可以很容易地理解为什么返回某些行而某些行不返回.
当where子句是这样的:
WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id);
Run Code Online (Sandbox Code Playgroud)
它只是意味着:返回订单表中具有相同ID的现有记录的行.
EXISTS 意味着子查询至少返回一行,确实如此。在这种情况下,它是一个相关子查询,因为它检查外表的supplier_id 到内表的supplier_id。该查询实际上表示:
SELECT 所有供应商 对于每个供应商 ID,查看该供应商是否存在订单 如果供应商不在订单表中,则从结果中删除该供应商 返回在订单表中具有相应行的所有供应商
在这种情况下,您可以使用 INNER JOIN 执行相同的操作。
SELECT suppliers.*
FROM suppliers
INNER
JOIN orders
ON suppliers.supplier_id = orders.supplier_id;
Run Code Online (Sandbox Code Playgroud)
小马的评论是正确的。您需要使用该连接进行分组,或者根据您需要的数据选择不同的。