2011-05-01 97 views
67

我在学习SQL,很难理解EXISTS语句。我碰到这句话对“存在”和不明白的地方:SQL EXISTS语句如何工作?

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

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

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

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

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

回答

0

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

选择所有供应商 对于每个供应商ID,看是否存在此供应商 订单如果供应商不存在订单表,从搜索结果中删除供应商 返回所有的供应商谁在订单表中有相应的行

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

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

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

+2

如果多个子记录与父项相关联,则内部联接将产生与EXISTS不同的结果 - 它们不相同。 – 2011-05-01 06:49:37

+0

我觉得我的混淆可能是我读过子查询与EXISTS返回true或false;但是这不可能是它返回的唯一的东西,对吧?子查询是否也返回所有“在订单表中具有相应行的供应商”?但如果是这样,EXISTS语句如何返回布尔结果?我在课本中读到的所有东西都只是说它只返回一个布尔结果,所以我很难将代码的结果与我被告知返回的结果进行协调。 – Dan 2011-05-01 09:37:13

+0

像函数一样读取EXISTS ... EXISTS(resultset)。如果结果集有行,则EXISTS函数将返回true,如果结果集为空,则返回false。基本上就是这样。 – 2011-05-01 19:49:49

0

你所描述的是一个所谓的查询与correlated subquery

(一般),它的东西,你应该尽量避免通过使用代替连接书面查询:

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

因为否则,子查询将每一行外部查询执行。

+2

这两种解决方案并不相同。如果'orders'中有多于一行符合连接条件,则JOIN会提供与EXISTS子查询不同的结果。 – 2011-05-01 06:39:52

+0

你说得对。我在 – 2011-05-02 06:00:31

+1

以上的查询中添加了一个“group by”,感谢替代解决方案。但是你是否建议如果在相关子查询和连接之间给出选项,我应该使用连接,因为它更高效? – 2014-04-23 10:04:14

5

如果你有一个where子句是这个样子:

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

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

当where子句是这样的:

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

它只是意味着:那些在用TE同一ID订单表中的现有记录返回行。

30

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

您认为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的直接替代品,因为如果有多个子记录与父级关联,则会有重复的父级记录。

+0

我仍然缺少一些东西。如果它在第一场比赛中退出,那么输出结果如何是o.supplierid = s.supplierid的所有结果?难道它不是只输出第一个结果吗? – Dan 2011-05-01 09:27:48

+1

@Dan:退出EXISTS,在第一次匹配时返回TRUE,因为供应商至少在ORDERS表中存在一次。如果您想查看供应商数据的重复,因为ORDERS中存在多个子关系,则必须使用JOIN。但大多数不希望重复,并且运行GROUP BY/DISTINCT可能会增加查询开销。 'EXISTS'比SQL SERVER上的'SELECT DISTINCT ... FROM SUPPLIERS JOIN ORDERS ...'更高效,最近还没有在Oracle或MySQL上进行过测试。 – 2011-05-01 16:40:57

+0

我有一个问题,是在外部查询中选择的每个记录的匹配。如果从供应商处选择5行,我们会从订单中取5次。 – 2016-01-29 15:20:04

18

可以使用产生相同的结果要么JOINEXISTSIN,或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 
+1

很好的答案,但也介意最好不要存在以避免相关性 – 2013-08-22 17:46:36

+0

如果供应商拥有10M行和订单有100M行,您认为哪个查询会运行得更快?为什么? – Teja 2017-04-11 19:08:15

62

把它看成是这样的:

对于来自Suppliers '每个' 行,检查是否有“存在'Order表中的一行符合条件Suppliers.supplier_id(这来自外部查询当前'行')= Orders.supplier_id。当您找到第一个匹配的行时,请停在那里 - WHERE EXISTS已得到满足。

外部查询和子查询之间的魔术联系在于Supplier_id从外部查询传递到评估的每一行的子查询。

或者,换句话说,子查询是针对外部查询的每个表行执行的。

它不像是子查询在整体上执行并获得'true/false',然后尝试将这个'true/false'条件与外部查询匹配。

+4

谢谢! “它不像总体上执行子查询并获得'真/假',然后试图将这个'真/假'条件与外部查询相匹配。”是真正为我清除它,我一直在想这就是子查询如何工作(和他们多次),但你说什么是有道理的,因为子查询依赖于外部查询,因此必须每行执行一次 – 2014-01-09 08:03:19

+1

@sojin完美解释,谢谢! – LP496 2016-04-17 23:00:27