Query

將 EXCEPT 與 NOT EXISTS 一起使用

  • January 9, 2019

在此處輸入圖像描述

SELECT DISTINCT cname
FROM account AS cust_account
WHERE NOT EXISTS ( SELECT type
                  FROM account
                  EXCEPT
                  SELECT type
                  FROM account
                  WHERE account.cname = cust_account.cname )

有人可以逐步解釋查詢如何產生問題所需的結果嗎?我只是在學習 NOT EXISTS 並且不確定它從括號中獲取什麼值以及 WHERE 子句所屬的位置。

這是範例表帳戶 在此處輸入圖像描述

查詢分為三個不同的部分。我會給它們貼上標籤,這樣我就可以更清楚地引用它們:

SELECT DISTINCT cname             -- Part A
FROM account AS cust_account
WHERE NOT EXISTS ( SELECT type    -- Part B
                  FROM account
                  EXCEPT
                  SELECT type    -- Part C
                  FROM account
                  WHERE account.cname = cust_account.cname )

首先是內部查詢。C 部分列出了目前由外部查詢(A 部分)考慮的客戶擁有的行的所有type值。account從概念上講,您可以認為 DBMS 讀取與外部查詢匹配的所有行,然後一次遍歷它們。對於每個外部行,它執行內部查詢。(實際上可能會發生更省時的事情,但它在邏輯上與此等價。)

C 部分有時稱為相關子查詢,因為它與來自外部查詢的值匹配(相關)。在這種情況下,它匹配 on cname。告訴 DBMS 將 C 部分與 A 部分匹配的是 WHERE 子句。它是cust_account在外部查詢中定義的別名。因為一個表 - account- 在語句中使用了三次,所以別名允許我們準確指定我們想要引用這三個中的哪一個。它是允許我們說“將 C 部分與 A 部分匹配”的別名。

B 部分列出了表中的所有typeaccount。這部分沒有 WHERE,因此它列出了所有使用者的所有帳戶,而不僅僅是外部查詢目前正在考慮的帳戶。這部分相關。

EXCEPT 獲取它上面的查詢結果(B 部分)並刪除它下面的查詢中出現的那些行(C 部分)。由於 B 部分是“數據庫中的所有類型”,而 C 部分是“目前 cname 擁有的所有類型”,因此“B 除了 C”是“除了目前 cname 擁有的類型之外的所有類型”。如果我們有一個所有類型的列表,並且我們刪除了 cname 擁有的那些,剩下的就是那些 cname 不擁有的類型。因此,如果內部查詢有任何行(對於目前 cname),我們知道至少有一種類型的帳戶不屬於 cname。

如果內部查詢有行,則 EXISTS() 返回 true。因此,如果內部查詢為空,則 NOT EXISTS() 返回 true。正如我們剛剛展示的,如果目前 cname 擁有所有類型的帳戶,則它將為空。因此,外部查詢列出了所有cname具有所有類型帳戶的帳戶 - 正如問題中所要求的那樣。

引用自:https://dba.stackexchange.com/questions/226626