MySQL5.7從入門到精通--------第七章讀書筆記(4)
7.5.1 帶ANY、SOME、ALL的子查詢
子查詢是指一個查詢語句巢狀在另外一個查詢語句中的查詢。
在SELECT子句中先計運算元查詢,子查詢結果作為來外外層另外一個查詢的過濾條件。即另外一個查詢的查詢條件就是子查詢中返回的資料記錄。
CREATE TABLE tbA(num1 INT NOT NULL); CREATE TABLE tbB(num2 INT NOT NULL); INSERT INTO tbA(num1) VALUES(1),(5),(13),(27); INSERT INTO tbB(num2) VALUES(6),(14),(11),(20);
ANY與SOME是一個意思,它表示只要滿足任意一個條件,就返回此結果。
SELECT
num1
FROM
tbA
WHERE
num1 > ANY (SELECT num2 FROM tbB)
ALL是滿足所有條件,才返回結果。
SELECT
num1
FROM
tbA
WHERE
num1 > ALL (SELECT num2 FROM tbB)
7.5.4 帶IN關鍵詞查詢
內查詢(巢狀查詢)返回的是一個數據列。
還是那個選導師的例子。
DROP TABLE IF EXISTS t_teacher; CREATE TABLE t_teacher( id INT(11) PRIMARY KEY AUTO_INCREMENT, teacName VARCHAR(255) NOT NULL UNIQUE, age INT(11) ); INSERT INTO t_teacher(teacName,age) VALUES('田教授資料庫原理',44),('秀芳姐C語言',31), ('黃金城通訊原理',36),('韓院長',55);
DROP TABLE IF EXISTS t_student; CREATE TABLE t_student( id INT(11), name VARCHAR(255), teacherId INT(11), CONSTRAINT fk_stu_teac FOREIGN KEY(teacherId) REFERENCES t_teacher(id) ); -- 每個學生選擇一個導師,也可以不選,即沒有導師 INSERT INTO t_student(id,name,teacherId) VALUES(1,'大宇',4),(2,'小雨',3), (3,'小大宇',2),(4,'學霸',NULL);
如上所示,除了學霸之外的所有學生都已經選好了導師,而學霸的導師是NULL,他要自立門戶。
現需求:查詢沒有選擇導師的學生,預期結果是查詢出來學霸。
SELECT
t_student.id,
t_student.name
FROM t_student
WHERE t_student.id NOT IN
(
SELECT t_student.id
FROM t_student
JOIN t_teacher ON t_student.teacherId = t_teacher.id
)
單獨執行子查詢,看下是什麼結果。
SELECT t_student.id
FROM t_student
JOIN t_teacher ON t_student.teacherId = t_teacher.id
原來子查詢返回的是一個序列,因此原來的SQL可以等價於
SELECT
t_student.id,
t_student.name
FROM t_student
WHERE t_student.id NOT IN
(
1,2,3
)
撥雲見日
原來,內層的巢狀查詢,或者說是子查詢,返回的原來是一個序列。這就可以解釋巢狀查詢返回多列結果會報錯的原因。
另外,帶巢狀查詢的SQL語句,其實是分兩步進行的,先執行巢狀查詢並返回序列,再執行外層查詢,條件為序列。
7.5.5 帶比較運算子的子查詢
現在的需求是:找出不是田教授帶的學生。
思路是先找到田教授的ID,再在學生表裡面判斷導師ID不是此ID的學生的值。
SELECT
t_student.id,
t_student.name,
t_student.teacherId AS 導師ID
FROM t_student
WHERE t_student.teacherId !=
(
SELECT t_teacher.id
FROM t_teacher WHERE t_teacher.teacName LIKE '%田%'
)
--單獨執行
SELECT t_teacher.id
FROM t_teacher WHERE t_teacher.teacName LIKE '%田%'
--結果為
--- id ---
--- 1 ---
根據查詢結果來看,好像是有點問題的,因為學霸的teacherId列的值是NULL,NULL != 1 的運算結果是NULL,所以在返回結果中沒有顯示學霸這個學生記錄。這也說明了在巢狀查詢中,注意NULL的列可能會影響查詢的結果。
本小節希望說明的是,子查詢其實就是返回的一個序列,外層查詢用子查詢的返回結果序列替換掉原來的子查詢部分即可。