EXISTS子查詢問題
今天SQL Server課講到帶有EXISTS運算子的子查詢
第一段的簡介是:
存在性子查詢使用EXISTS運算子,EXISTS子查詢並不返回任何資料,只產生邏輯值TRUE或FALSE。由於存在性子查詢只是檢測是否存在符合條件的記錄,因此不需要列出具體的列名,選擇列幾乎都由(*)組成
給出的語法是:
WHERE [NOT] EXISTS(subquery)
給出的例子是:
查詢所有選修了SQL SERVER課程的學生的學號,課程號,課程名和成績,程式碼如下
USE CJGL GO SELECT 學號,scoreinfo.課程號,課程名,成績 FROM scoreinfo,classinfo WHERE scoreinfo.課程號=classinfo.課程號 AND EXISTS(SELECT * FROM CLASSINFO WHERE 課程名='SQL Server')
給出的結果是
學號 課程號 課程名 成績
----------- ---------- -------------------- ------
980003 001 SQL Server 67
980007 001 SQL Server 78
這個應該是書上想要這段程式碼得出的結果,不過我們自己輸入這段程式碼得出的結果是
學號 課程號 課程名 成績 ----------- ---------- -------------------- ------ 980003 001 SQL Server 67 980004 002 Delphi 87 980005 003 Java程式設計 55 980006 002 Delphi 67 980007 001 SQL Server 78 980001 002 Delphi 88 980002 003 Java程式設計 78 980004 003 Java程式設計 86
老師說課本上的例子錯了,然後又重新寫了一個方法查到書上想要我們得到的結果。不過我感覺書上給的寫法不應該完全是錯的,我就以書上的寫法為基礎改了又改,想找到EXISTS子查詢的規律。
我發現以這樣的方式寫,主查詢條件不變的情況下總是能得到想要的結果
USE CJGL
SELECT 學號,scoreinfo.課程號,課程名,成績
FROM scoreinfo,classinfo
WHERE scoreinfo.課程號=classinfo.課程號
AND EXISTS(SELECT * WHERE 課程名='SQL Server')
跟書上的不同是EXISTS子查詢語句裡 *SELECT * 後不加 FROM classinfo
因為如果按書上說的,EXISTS子查詢不返回資料,只返回邏輯值FALSE和TRUE,那感覺EXISTS語句的存在根本沒什麼意義
因為主查詢條件不變的情況下,如果EXISTS的返回值為FALSE,那麼整個查詢就無資料返回,比如
USE CJGL
SELECT 學號,scoreinfo.課程號,課程名,成績
FROM scoreinfo,classinfo
WHERE scoreinfo.課程號=classinfo.課程號
AND EXISTS(SELECT * FROM CLASSINFO WHERE 1<>1)
如果EXISTS的返回值為TRUE,那麼就會把所有符合主查詢的值返回,但並不是我們想得到的結果,比如:
USE CJGL
SELECT 學號,scoreinfo.課程號,課程名,成績
FROM scoreinfo,classinfo
WHERE scoreinfo.課程號=classinfo.課程號
AND EXISTS(SELECT * FROM CLASSINFO WHERE 1=1)
我得出結論EXISTS子查詢不返回資料,只返回邏輯值FALSE和TRUE,返回值為TRUE則輸出資料,返回值為FALSE則不輸出資料這句描述是不對的,也許是對的,但絕對是片面的。要麼一行記錄都不輸出,要麼輸出的記錄只符合主查詢的條件,這樣EXISTS子查詢就沒有存在的意義了。
然後在百度上找了好多跟EXISTS子查詢語句有關的文章跟回答。發現了一個關鍵的知識點,EXISTS子查詢分關聯子查詢和非關聯子查詢
大概意思是:
EXISTS關聯子查詢是把符合主查詢條件的記錄再根據子查詢的條件再次判斷,如果子查詢的返回值為TRUE,也就是符合子查詢條件,那麼輸出此行記錄
EXISTS非關聯子查詢是子查詢是獨立的,可以跟外部查詢沒有任何關係,只是用來返回邏輯值TRUE 或者 FALSE
然後我得出結論EXISTS非關聯子查詢只執行一次,返回的邏輯值適用於所有符合外部查詢的記錄,要麼所有都是TRUE要麼所有都是FALSE,因此對外部查詢得出的記錄是沒有二次篩選的效果的。
這也印證了EXISTS子查詢不返回資料,只返回邏輯值FALSE和TRUE,返回值為TRUE則輸出資料,返回值為FALSE則不輸出資料這句話是片面的。
根據上面得出的結論我又用不同的查詢條件做了幾次實驗,得出的結果都是跟預期相符的。
但是還有一個問題,EXISTS怎麼樣用才是關聯子查詢,怎麼樣用是非關聯的子查詢。
我發現這個例子中,如果把子查詢中的 FROM TABLE_NAME刪去,總能實現對外部查詢結果的二次篩選
SELECT * WHERE 課程名='SQL Server'
如果加上FROM TABLE_NAME,就成了一個輸出判斷,要麼輸出所有,要麼一條記錄也不輸出。
不過總感覺沒有FROM TABLE_NAME的SELECT語句怪怪的,我猜測可能是跟外部查詢是個連個錶鏈接查詢有關,語句是預設對外部查詢得出的臨時表進行關聯子查詢。
剛開始學SQL Server,還是有點雲裡霧裡,我對EXISTS子查詢語句的理解大概是這樣,今天上午上課講的,到晚上才找到對結果合理的解釋,搞得我一天茶飯不思。要是有理解的不對的地方希望前輩們指點一二!!!