將 EXCEPT 與 NOT EXISTS 一起使用
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 部分列出了表中的所有
type
值account
。這部分沒有 WHERE,因此它列出了所有使用者的所有帳戶,而不僅僅是外部查詢目前正在考慮的帳戶。這部分不相關。EXCEPT 獲取它上面的查詢結果(B 部分)並刪除它下面的查詢中出現的那些行(C 部分)。由於 B 部分是“數據庫中的所有類型”,而 C 部分是“目前 cname 擁有的所有類型”,因此“B 除了 C”是“除了目前 cname 擁有的類型之外的所有類型”。如果我們有一個所有類型的列表,並且我們刪除了 cname 擁有的那些,剩下的就是那些 cname 不擁有的類型。因此,如果內部查詢有任何行(對於目前 cname),我們知道至少有一種類型的帳戶不屬於 cname。
如果內部查詢有行,則 EXISTS() 返回 true。因此,如果內部查詢為空,則 NOT EXISTS() 返回 true。正如我們剛剛展示的,如果目前 cname 擁有所有類型的帳戶,則它將為空。因此,外部查詢列出了所有
cname
具有所有類型帳戶的帳戶 - 正如問題中所要求的那樣。