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。
您可以使用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
如果你有一个如下所示的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
否则,子查询将在外部查询中的每一行执行。