全面講解MySQL子查詢(xún)
前言
子查詢(xún)指一個(gè)查詢(xún)語(yǔ)句嵌套在另一個(gè)查詢(xún)語(yǔ)句內(nèi)部的查詢(xún),這個(gè)特性從MySQL 4.1開(kāi)始引入。
SQL 中子查詢(xún)的使用大大增強(qiáng)了 SELECT 查詢(xún)的能力,因?yàn)楹芏鄷r(shí)候查詢(xún)需要從結(jié)果集中獲取數(shù)據(jù),或者需要從同一個(gè)表中先計(jì)算得出一個(gè)數(shù)據(jù)結(jié)果,然后與這個(gè)數(shù)據(jù)結(jié)果(可能是某個(gè)標(biāo)量,也可能是某個(gè)集合)進(jìn)行比較。
一、需求分析與問(wèn)題解決
1、實(shí)際問(wèn)題
現(xiàn)有解決方式:
#方式一: SELECT salary FROM employees WHERE last_name = 'Abel'; SELECT last_name,salary FROM employees WHERE salary > 11000;
#方式二:自連接 SELECT e2.last_name,e2.salary FROM employees e1,employees e2 WHERE e1.last_name = 'Abel' AND e1.`salary` < e2.`salary`
#方式三:子查詢(xún) SELECT last_name,salary FROM employees WHERE salary > ( SELECT salary FROM employees WHERE last_name = 'Abel' );
2、子查詢(xún)的基本使用
子查詢(xún)的基本語(yǔ)法結(jié)構(gòu):
子查詢(xún)(內(nèi)查詢(xún))在主查詢(xún)之前一次執(zhí)行完成。
子查詢(xún)的結(jié)果被主查詢(xún)(外查詢(xún))使用 。
注意事項(xiàng)
- 子查詢(xún)要包含在括號(hào)內(nèi)
- 將子查詢(xún)放在比較條件的右側(cè)
- 單行操作符對(duì)應(yīng)單行子查詢(xún),多行操作符對(duì)應(yīng)多行子查詢(xún)
3、子查詢(xún)的分類(lèi)
1. 分類(lèi)方式1:
我們按內(nèi)查詢(xún)的結(jié)果返回一條還是多條記錄,將子查詢(xún)分為單行子查詢(xún)、多行子查詢(xún)。
•單行子查詢(xún)
•多行子查詢(xún)
2. 分類(lèi)方式2:
我們按內(nèi)查詢(xún)是否被執(zhí)行多次,將子查詢(xún)劃分為相關(guān)(或關(guān)聯(lián))子查詢(xún)和不相關(guān)(或非關(guān)聯(lián))子查詢(xún)。
子查詢(xún)從數(shù)據(jù)表中查詢(xún)了數(shù)據(jù)結(jié)果,如果這個(gè)數(shù)據(jù)結(jié)果只執(zhí)行一次,然后這個(gè)數(shù)據(jù)結(jié)果作為主查詢(xún)的條件進(jìn)行執(zhí)行,那么這樣的子查詢(xún)叫做不相關(guān)子查詢(xún)。
同樣,如果子查詢(xún)需要執(zhí)行多次,即采用循環(huán)的方式,先從外部查詢(xún)開(kāi)始,每次都傳入子查詢(xún)進(jìn)行查詢(xún),然后再將結(jié)果反饋給外部,這種嵌套的執(zhí)行方式就稱(chēng)為相關(guān)子查詢(xún)。
二、單行子查詢(xún)
1、單行比較操作符
2、代碼示例
題目:查詢(xún)工資大于149號(hào)員工工資的員工的信息
題目:返回job_id與141號(hào)員工相同,salary比143號(hào)員工多的員工姓名,job_id和工資
SELECT last_name, job_id, salary FROM employees WHERE job_id = (SELECT job_id FROM employees WHERE employee_id = 141) AND salary > (SELECT salary FROM employees WHERE employee_id = 143);
題目:返回公司工資最少的員工的last_name,job_id和salary
SELECT last_name, job_id, salary
FROM employees
WHERE salary =
(SELECT MIN(salary)
FROM employees);
題目:查詢(xún)與141號(hào)或174號(hào)員工的manager_id和department_id相同的其他員工的employee_id,manager_id,department_id
實(shí)現(xiàn)方式1:不成對(duì)比較
SELECT employee_id, manager_id, department_id FROM employees WHERE manager_id IN (SELECT manager_id FROM employees WHERE employee_id IN (174,141)) AND department_id IN (SELECT department_id FROM employees WHERE employee_id IN (174,141)) AND employee_id NOT IN(174,141);
實(shí)現(xiàn)方式2:成對(duì)比較
SELECT employee_id, manager_id, department_id FROM employees WHERE (manager_id, department_id) IN (SELECT manager_id, department_id FROM employees WHERE employee_id IN (141,174)) AND employee_id NOT IN (141,174);
3、HAVING 中的子查詢(xún)
- 首先執(zhí)行子查詢(xún)。
- 向主查詢(xún)中的HAVING 子句返回結(jié)果。
題目:查詢(xún)最低工資大于50號(hào)部門(mén)最低工資的部門(mén)id和其最低工資
SELECT department_id, MIN(salary) FROM employees GROUP BY department_id HAVING MIN(salary) > (SELECT MIN(salary) FROM employees WHERE department_id = 50);
4、CASE中的子查詢(xún)
在CASE表達(dá)式中使用單列子查詢(xún):
題目:顯式員工的employee_id,last_name和location。其中,若員工department_id與location_id為1800的department_id相同,則location為’Canada’,其余則為’USA’。
SELECT employee_id, last_name, (CASE department_id WHEN (SELECT department_id FROM departments WHERE location_id = 1800) THEN 'Canada' ELSE 'USA' END) location FROM employees;
5、子查詢(xún)中的空值問(wèn)題
SELECT last_name, job_id FROM employees WHERE job_id = (SELECT job_id FROM employees WHERE last_name = 'Haas');
子查詢(xún)不返回任何行
6、非法使用子查詢(xún)
SELECT employee_id, last_name FROM employees WHERE salary = (SELECT MIN(salary) FROM employees GROUP BY department_id);
多行子查詢(xún)使用單行比較符
三、多行子查詢(xún)
- 也稱(chēng)為集合比較子查詢(xún)
- 內(nèi)查詢(xún)返回多行
- 使用多行比較操作符
1、多行比較操作符
體會(huì) ANY 和 ALL 的區(qū)別
2、代碼示例
題目:返回其它job_id中比job_id為‘IT_PROG’部門(mén)任一工資低的員工的員工號(hào)、姓名、job_id 以及salary
題目:返回其它job_id中比job_id為‘IT_PROG’部門(mén)所有工資都低的員工的員工號(hào)、姓名、job_id以及salary
題目:查詢(xún)平均工資最低的部門(mén)id
#方式1: SELECT department_id FROM employees GROUP BY department_id HAVING AVG(salary) = ( SELECT MIN(avg_sal) FROM ( SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id ) dept_avg_sal )
#方式2: SELECT department_id FROM employees GROUP BY department_id HAVING AVG(salary) <= ALL ( SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id )
3、空值問(wèn)題
SELECT last_name FROM employees WHERE employee_id NOT IN ( SELECT manager_id FROM employees );
四、相關(guān)子查詢(xún)
1、相關(guān)子查詢(xún)執(zhí)行流程
如果子查詢(xún)的執(zhí)行依賴(lài)于外部查詢(xún),通常情況下都是因?yàn)樽硬樵?xún)中的表用到了外部的表,并進(jìn)行了條件關(guān)聯(lián),因此每執(zhí)行一次外部查詢(xún),子查詢(xún)都要重新計(jì)算一次,這樣的子查詢(xún)就稱(chēng)之為關(guān)聯(lián)子查詢(xún)。
相關(guān)子查詢(xún)按照一行接一行的順序執(zhí)行,主查詢(xún)的每一行都執(zhí)行一次子查詢(xún)。
說(shuō)明:子查詢(xún)中使用主查詢(xún)中的列
2、代碼示例
題目:查詢(xún)員工中工資大于本部門(mén)平均工資的員工的last_name,salary和其department_id
1. 方式一:相關(guān)子查詢(xún)
2. 方式二:在 FROM 中使用子查詢(xún)
SELECT last_name,salary,e1.department_id FROM employees e1,(SELECT department_id,AVG(salary) dept_avg_sal FROM employees GROUP BY department_id) e2 WHERE e1.`department_id` = e2.department_id AND e2.dept_avg_sal < e1.`salary`;
from型的子查詢(xún):子查詢(xún)是作為from的一部分,子查詢(xún)要用()引起來(lái),并且要給這個(gè)子查詢(xún)?nèi)e名,把它當(dāng)成一張“臨時(shí)的虛擬的表”來(lái)使用。
在ORDER BY 中使用子查詢(xún):
題目:查詢(xún)員工的id,salary,按照department_name 排序
SELECT employee_id,salary FROM employees e ORDER BY ( SELECT department_name FROM departments d WHERE e.`department_id` = d.`department_id` );
題目:若employees表中employee_id與job_history表中employee_id相同的數(shù)目不小于2,輸出這些相同id的員工的employee_id,last_name和其job_id
SELECT e.employee_id, last_name,e.job_id FROM employees e WHERE 2 <= (SELECT COUNT(*) FROM job_history WHERE employee_id = e.employee_id);
3、EXISTS 與 NOT EXISTS關(guān)鍵字
- 關(guān)聯(lián)子查詢(xún)通常也會(huì)和 EXISTS操作符一起來(lái)使用,用來(lái)檢查在子查詢(xún)中是否存在滿(mǎn)足條件的行。
- 如果在子查詢(xún)中不存在滿(mǎn)足條件的行:
- 條件返回 FALSE
- 繼續(xù)在子查詢(xún)中查找
- 如果在子查詢(xún)中存在滿(mǎn)足條件的行:
- 不在子查詢(xún)中繼續(xù)查找
- 條件返回 TRUE
- NOT EXISTS關(guān)鍵字表示如果不存在某種條件,則返回TRUE,否則返回FALSE。
題目:查詢(xún)公司管理者的employee_id,last_name,job_id,department_id信息
方式一:
SELECT employee_id, last_name, job_id, department_id FROM employees e1 WHERE EXISTS ( SELECT * FROM employees e2 WHERE e2.manager_id = e1.employee_id);
方式二:自連接
SELECT DISTINCT e1.employee_id, e1.last_name, e1.job_id, e1.department_id FROM employees e1 JOIN employees e2 WHERE e1.employee_id = e2.manager_id;
方式三:
SELECT employee_id,last_name,job_id,department_id FROM employees WHERE employee_id IN ( SELECT DISTINCT manager_id FROM employees );
題目:查詢(xún)departments表中,不存在于employees表中的部門(mén)的department_id和department_name
SELECT department_id, department_name FROM departments d WHERE NOT EXISTS (SELECT 'X' FROM employees WHERE department_id = d.department_id);
4、相關(guān)更新
UPDATE table1 alias1 SET column = (SELECT expression FROM table2 alias2 WHERE alias1.column = alias2.column);
使用相關(guān)子查詢(xún)依據(jù)一個(gè)表中的數(shù)據(jù)更新另一個(gè)表的數(shù)據(jù)。
題目:在employees中增加一個(gè)department_name字段,數(shù)據(jù)為員工對(duì)應(yīng)的部門(mén)名稱(chēng)
# 1) ALTER TABLE employees ADD(department_name VARCHAR2(14)); # 2) UPDATE employees e SET department_name = (SELECT department_name FROM departments d WHERE e.department_id = d.department_id);
5、相關(guān)刪除
DELETE FROM table1 alias1 WHERE column operator (SELECT expression FROM table2 alias2 WHERE alias1.column = alias2.column);
使用相關(guān)子查詢(xún)依據(jù)一個(gè)表中的數(shù)據(jù)刪除另一個(gè)表的數(shù)據(jù)。
題目:刪除表employees中,其與emp_history表皆有的數(shù)據(jù)
DELETE FROM employees e WHERE employee_id in (SELECT employee_id FROM emp_history WHERE employee_id = e.employee_id);
五、拋一個(gè)思考題
問(wèn)題: 誰(shuí)的工資比Abel的高?
解答:
#方式1:自連接 SELECT e2.last_name,e2.salary FROM employees e1,employees e2 WHERE e1.last_name = 'Abel' AND e1.`salary` < e2.`salary`
#方式2:子查詢(xún) SELECT last_name,salary FROM employees WHERE salary > ( SELECT salary FROM employees WHERE last_name = 'Abel' );
問(wèn)題: 以上兩種方式有好壞之分嗎?
解答: 自連接方式好!
題目中可以使用子查詢(xún),也可以使用自連接。一般情況建議你使用自連接,因?yàn)樵谠S多 DBMS 的處理過(guò)程中,對(duì)于自連接的處理速度要比子查詢(xún)快得多。
可以這樣理解:子查詢(xún)實(shí)際上是通過(guò)未知表進(jìn)行查詢(xún)后的條件判斷,而自連接是通過(guò)已知的自身數(shù)據(jù)表進(jìn)行條件判斷,因此在大部分 DBMS 中都對(duì)自連接處理進(jìn)行了優(yōu)化。
到此這篇關(guān)于全面講解MySQL子查詢(xún)的文章就介紹到這了,更多相關(guān)MySQL子查詢(xún) 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- MySQL子查詢(xún)的實(shí)現(xiàn)示例
- mysql數(shù)據(jù)庫(kù)SQL子查詢(xún)(史上最詳細(xì))
- MySQL復(fù)合查詢(xún)(多表查詢(xún)、子查詢(xún))的實(shí)現(xiàn)
- MySQL中order by在子查詢(xún)中失效的問(wèn)題解決方案
- 關(guān)于Mysql子查詢(xún)的三個(gè)應(yīng)用場(chǎng)景
- mysql子查詢(xún)(單行子查詢(xún),多行子查詢(xún),多列子查詢(xún))
- 一文了解MySQL的四大子查詢(xún)
- 一文帶你了解MySQL中的子查詢(xún)
- MySQL實(shí)例講解子查詢(xún)的使用
- MySQL子查詢(xún)?cè)敿?xì)教程
- MySQL中子查詢(xún)的具體實(shí)現(xiàn)
相關(guān)文章
MySQL 5.7 mysql command line client 使用命令詳解
這篇文章主要介紹了MySQL 5.7 mysql command line client 使用命令,需要的朋友可以參考下2017-06-06關(guān)于django連接mysql數(shù)據(jù)庫(kù)并進(jìn)行數(shù)據(jù)庫(kù)的創(chuàng)建的問(wèn)題
這篇文章主要介紹了django連接mysql數(shù)據(jù)庫(kù)并進(jìn)行數(shù)據(jù)庫(kù)的創(chuàng)建,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06使用bin-log日志還原數(shù)據(jù)庫(kù)的例子
使用bin-log日志還原數(shù)據(jù)庫(kù)的例子,供大家學(xué)習(xí)參考2013-02-02