SQL基础系列(五)——子查询
子查詢是在一個完整的查詢語句中,嵌套不同功能的小查詢,從而完成復雜查詢的一種編寫形式。本部分主要介紹非關聯子查詢,關聯子查詢的適用場景,語句寫法,執行邏輯及相對應的注意事項。
目錄
1.非關聯子查詢
1.1執行邏輯
1.2在WHERE子句中使用子查詢
1.2.1子查詢返回一個具體數據
1.2.2子查詢返回一條數據
1.2.3子查詢返回多行單列數據
1.3在HAVING子句中使用子查詢
1.4在FROM子句中使用子查詢
2.關聯子查詢
2.1在細分的組內進行比較
2.2使用EXISTS,NOT EXISTS時使用關聯子查詢
1.非關聯子查詢
在SELECT子句、GROUP BY子句、HAVING子句、ORDER BY子句中均可使用子查詢語句,較常用的是WHERE子句、HAVING子句和FROM子句。
1.1執行邏輯
在非關聯子查詢中,子查詢語句可以獨立執行,查詢結果是一個數據,一條數據,或者一張臨時數據表,主查詢可使用子查詢結果進行操作。
1.2在WHERE子句中使用子查詢
在WHERE子句中,通常使用子查詢結果作為篩選條件。
1.2.1子查詢返回一個具體數據
題目1:求table表中工資高于平均工資的數據。
在WHERE子句中不可以使用函數,因此想要求大于某個統計值的數據,不能使用如下寫法:
🙅SELECT * FROM table WHERE salary>avg(salary);
正確的示例如下:
🙆SELECT * FROM table WHERE salary>(SELECT?avg(salary) FROM table);
在上面標紅的子查詢語句中,返回結果是一個平均值,主查詢語句在執行時判斷平均工資是否大于平均值,符合條件則作為查詢結果展示。
題目2:求table1表中和'ELLEN'職位一樣的數據
思路同上,使用子查詢語句求出'ELLEN'的職位,再將其作為篩選條件,判斷職位與其一致的數據。
🙆SELECT * FROM table1
? ? ? WHERE job=(SELECT job FROM table1 WHERE name='ELLEN');
注釋:
- 在WHERE子句中可使用多個子查詢,支持多個條件中分別使用子查詢語句;
- 子查詢語句可以進行嵌套;?
1.2.2子查詢返回一條數據
子查詢返回一條數據,即多個屬性,使用多個屬性值進行數據判斷,示例如下:
?題目1:求table表中與'ELLEN'工作及工資均一致的數據。
題目解析:先找出'ELLEN'的工作及工資,然后判斷數據中同時和這兩個屬性一致的數據。
🙆SELECT * FROM table1
? ? ? WHERE (job,salary)=(SELECT job,salary?FROM table1 WHERE name='ELLEN');
語句返回的結果中包含ELLEN及與其工作和工資一致的數據。
1.2.3子查詢返回多行單列數據
此種情況下,子查詢返回多數據時一個數據的范圍,在WHERE子句中通過數據范圍進行篩選時,需用操作符IN、ANY、ALL
(1)IN
題目1:求每個部門最低工資,并查找出與最低工資相同的員工信息
🙆SELECT * FROM table1
? ? ? WHERE sal IN (SELECT min(sal) FROM?table1 GROUP BY deptno);
子查詢中返回的是每個部門的最低工資,一列多行。根據子查詢的結果,判斷工資在子查詢數據范圍內的數據。
??:IN,或者NOT IN 后的數據范圍內存在值為NULL的數據,則查詢結果為空。
(2)ANY
題目1:求每個部門最低工資,并查找出大于任意一個部門最低工資的員工信息
🙆SELECT * FROM table1
? ? ? WHERE sal?>ANY?(SELECT min(sal) FROM?table1 GROUP BY deptno);
>ANY:大于其后數據范圍內最小值
<ANY:小于其后數據范圍內最大值
=ANY:效果相當于IN
<>ANY:🙅錯誤用法?
(3)ALL
題目1:求每個部門最低工資,并查找出比所有部門最低工資都大的員工信息
🙆SELECT * FROM table1
? ? ? WHERE sal?>ALL?(SELECT min(sal) FROM?table1 GROUP BY deptno);
<>ALL:相當于NOT IN
>ALL:大于其后數據范圍內的最大值
<ALL:小于其后數據范圍內的最小值
=ALL:🙅錯誤用法
1.3在HAVING子句中使用子查詢
在HAVING子句中使用子查詢,即對分組進行過濾,子查詢往往返回的都是一個具體的數據(單行單列)。
題目:篩選出平均工資大于全體員工平均工資的部門
🙆SELECT deptno,?avg(sal) FROM table1
? ? ??GROUP BY?deptno
? ? ? HAVING avg(sal)>?(SELECT avg(sal) FROM?table1);
??:分組語句中,SELECT后只能跟分組字段、函數及常數,不能使用非分組函數;
解析思路:
HAVING子句中限定組的篩選條件。題目中,需計算出各部門的平均工資,并篩選出符合條件的部門(部門就是分組標準)。
子查詢語句中,計算出部門整體的平均工資,然后將各部門的平均工資與之對比。
1.4在FROM子句中使用子查詢
FROM子句限定查詢的數據表,使用子查詢,即將子查詢的結果作為一張臨時的數據表使用。
題目:emp表:部門編號(deptno),姓名(name),工資(sal),職位(job),雇傭日期(hiredate)
篩選出公司每個員工的編號,姓名,工資,職位,雇傭日期,部門最大工資,部門最小工資
題目分析:
要求的取值結果中,包含分組統計的內容(部門最大最小值)及數據表其他字段。
分組情況下,SELECT子句僅可跟分組字段,函數,常量。題目需要展示非分組字段。
因此,需要把分組統計的結果單獨查詢出作為一個數據表,將此表與原表進行聯結。
SELECT e.deptno,e.name,e.sal,e.job,e.hiredate,t.max,t.min
FROM emp e,
? ? ? ? ? ?(SELECT deptno,max(sal) max,min(sal) min FROM emp GROUP BY deptno) t
WHERE e.deptno=t.deptno;
2.關聯子查詢
關聯子查詢:子查詢不可獨立執行,子查詢中使用主查詢的列作為條件。先執行外部查詢,將外部查詢出的每條數據傳遞給子查詢語句執行,子查詢執行一次返回執行結果后,主查詢根據子查詢結果進行決策。
2.1在細分的組內進行比較
題目1:根據各個部門的平均工資,查詢超過本部門平均工資的員工信息。
🙅錯誤寫法
🙅SELECT * FROM table1
? ? ? WHERE sal?>(SELECT avg(sal) FROM?table1 GROUP BY deptno);
錯誤原因:在子查詢中查每個部門的平均工資,但是是多行多列的結果。WHERE條件后,當子查詢結果為單行單列時,才能進行正常比較。
🙆正確寫法
🙆SELECT * FROM table1 t1
? ? ? WHERE sal?>(SELECT avg(sal) FROM?table1 t2 WHERE t1.deptno=t2.deptno);
上面子查詢的語句為關聯子查詢,子查詢的where子句中使用了主查詢的字段列作為限定條件。
在執行這條語句時,取出主查詢中的一條員工數據,傳入子查詢中,在子查詢中篩選此員工同部門的數據,計算部門的平均工資。主查詢中將此員工工資和同部門的平均工資對比,符合條件則保留員工數據。然后再取下一個員工,重復執行以上過程。
2.2使用EXISTS,NOT EXISTS時使用關聯子查詢
題目:用戶表customer 訂單表order?
求沒有下過訂單的客戶的信息
🙆SELECT * FROM customer c
? ? ? WHERE not exists?
?? ? ? ? ? ? ? ? ? ??(SELECT customer_id?FROM order o?WHERE c.customer_id=o.customer_id);
假設張三下了訂單,李四沒有下訂單。
那么在語句執行的時候,通過外查詢語句取張三的信息,通過子查詢中的WHERE判斷,子查詢可取出一條數據,不符合not exists,此條數據不保留。
取李四的數據,通過子查詢中的where判斷,子查詢無符合條件的數據,符合not exists,此條數據保留。
EXISTS,NOT EXISTS還有更復雜的用法,后續可以單獨介紹一下。看到一篇講的比較詳細的文章,大家如果有興趣可以移步至:
EXISTS,NOT EXISTS
總結
以上是生活随笔為你收集整理的SQL基础系列(五)——子查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最新07高考零分作文片断
- 下一篇: 小白看完都会了!mysql面试题sql语