2011-05-01 62 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