SQL EXISTS语句如何工作?

我正在尝试学习SQL,并且很难理解EXISTS语句。 我遇到了这个关于“存在”的引用,不明白的地方:

使用exists操作符,子查询可以返回零个,一个或多个行,条件只是检查子查询是否返回任何行。 如果您查看子查询的select子句,您将看到它由单个文字(1)组成; 由于包含查询中的条件只需要知道返回了多less行,所以子查询返回的实际数据是不相关的。

我不明白的是外部查询如何知道子查询的哪一行? 例如:

SELECT * FROM suppliers WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id); 

据我所知,如果供应商和订单表中的ID匹配,则子查询将返回true,并输出供应商表中匹配行的所有列。 我没有得到的是子查询如何传递哪个特定的行(可以说供应商ID为25的行)应该被打印,如果只返回true或false。

在我看来,外部查询和子查询之间没有关系。

这样想:

对于来自Suppliers “每一行”,检查Order表中是否存在符合条件Suppliers.supplier_id (来自Outer query = Orders.supplier_id ') = Orders.supplier_id的行。 当你find第一个匹配的行时,就在那里停下来 – WHERE EXISTS已经满足了。

外部查询和子查询之间的魔术链接在于Supplier_id从外部查询传递到子查询,以便评估每一行。

或者,换句话说,对于外层查询的每个表行都会执行子查询。

它不像是子查询在整体上执行,并获得“真/假”,然后试图匹配这个“真/假”条件与外部查询。

在我看来,外部查询和子查询之间没有关系。

你认为EXISTS例子中的WHERE子句在做什么? 如果供应商的引用不在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) 

…应该通过零错误达到一个分区,但是不会。 WHERE子句是EXISTS子句中最重要的一部分。

另外请注意,JOIN并不是EXISTS的直接替代品,因为如果有多个子logging与父项关联,则会有重复的父logging。

您可以使用JOINEXISTSININTERSECT生成相同的结果:

 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 

如果你有一个如下所示的where子句:

 WHERE id in (25,26,27) -- and so on 

你可以很容易地理解为什么有些行被返回,有些不是。

当where子句是这样的:

 WHERE EXISTS (select * from orders where suppliers.supplier_id = orders.supplier_id); 

它只是意味着:返回订单表中具有相同ID的现有logging的行。

EXISTS意味着子查询返回至less一行,就是这样。 在这种情况下,它是一个相关的子查询,因为它将外部表的supplier_id检查为内部表的supplier_id。 这个查询说实际上是这样的:

select所有供应商对于每个供应商ID,查看该供应商的订单是否存在如果供应商不在订单表中,则从结果中删除供应商返回在订单表中具有相应行的所有供应商

在这种情况下,你可以用INNER JOIN做同样的事情。

 SELECT suppliers.* FROM suppliers INNER JOIN orders ON suppliers.supplier_id = orders.supplier_id; 

小马评论是正确的。 您需要对该连接进行分组,或根据所需的数据select不同的分组。

你所描述的是一个所谓的查询与相关的子查询 。

(通常)通过使用连接来编写查询,您应该尝试避免这种情况:

 SELECT suppliers.* FROM suppliers JOIN orders USING supplier_id GROUP BY suppliers.supplier_id 

否则,子查询将在外部查询中的每一行执行。