MySQL子查詢?cè)斀?單行子查詢、多行子查詢與相關(guān)子查詢)
0.概念
子查詢:一個(gè)查詢語(yǔ)句嵌套在另一個(gè)查詢語(yǔ)句內(nèi)部
1.需求分析與問(wèn)題解決
1.1提出具體問(wèn)題:
# 法一:效率低 SELECT last_name,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 e2.`salary` > e1.`salary` AND e1.`last_name` = 'Abel'; #法三:子查詢 SELECT last_name,salary FROM employees WHERE salary > ( SELECT salary FROM employees WHERE last_name = 'ABEL' ); # 稱謂的規(guī)范:外查詢(主查詢),內(nèi)查詢(子查詢)
1.2 子查詢的基本使用: 子查詢的基本語(yǔ)法結(jié)構(gòu):
子查詢(內(nèi)查詢)在主查詢之前一次執(zhí)行完成。
子查詢的結(jié)果被主查詢(外查詢)使用 。
注意事項(xiàng)
- 子查詢要包含在括號(hào)內(nèi)
- 將子查詢放在比較條件的右側(cè)
- 單行操作符對(duì)應(yīng)單行子查詢,多行操作符對(duì)應(yīng)多行子查詢
1.3 子查詢的分類
角度一:從內(nèi)查詢返回結(jié)果的條目數(shù)
單行子查詢 | 多行子查詢 |
---|---|
子查詢結(jié)果只有一個(gè)數(shù)據(jù) | 子查詢數(shù)據(jù)返回多個(gè) |
角度二:內(nèi)查詢是否被執(zhí)行多次
相關(guān)子查詢 | 不相關(guān)子查詢 |
---|---|
查詢工資大于本部門平均工資的員工信息 | 查詢工資大于本公司平均工資的員工信息 |
2.單行子查詢
操作符 | 含義 |
---|---|
= | equal to |
> | greater than |
>= | greater than or equal to |
< | less than |
<= | less than or equal to |
<> | not equal to |
2.1實(shí)例:
# 查詢工資大于149號(hào)員工工資的信息 SELECT salary,last_name,employee_id FROM employees WHERE salary > ( SELECT salary FROM employees WHERE employee_id = 149 ); # 返回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 ); # 查詢與141號(hào)員工的manager_id和department_id相同的其他員工的employee_id, # manager_id,department_id SELECT employee_id,manager_id,department_id FROM employees WHERE manager_id = (SELECT manager_id FROM employees WHERE employee_id = 141) AND department_id =(SELECT department_id FROM employees WHERE employee_id = 141) AND employee_id <> 141; #方式二:成對(duì)查詢 SELECT employee_id,manager_id,department_id FROM employees WHERE (manager_id,department_id) = ( SELECT manager_id,department_id FROM employees WHERE employee_id = 141 ) AND employee_id <> 141; # 查詢最低工資大于50號(hào)部門最低工資的部門id和其最低工資 SELECT MIN(salary),department_id,salary FROM employees GROUP BY department_id HAVING MIN(salary) > ( SELECT MIN(salary) FROM employees WHERE department_id = 50 ) ORDER BY MIN(salary) DESC; # 題目:顯式員工的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;
2.2空值問(wèn)題
SELECT last_name FROM employees WHERE employee_id NOT IN ( SELECT manager_id FROM employees );
內(nèi)查詢的結(jié)果是NULL空值,不會(huì)報(bào)錯(cuò),但是也不會(huì)顯示數(shù)據(jù)
2.3非法使用子查詢
SELECT employee_id, last_name FROM employees WHERE salary = (SELECT MIN(salary) FROM employees GROUP BY department_id);
這里內(nèi)查詢返回的結(jié)果是一列數(shù)據(jù),不能使用等于號(hào)連接,必須使用in
3.多行子查詢
- 也稱為集合比較子查詢
- 內(nèi)查詢返回多行
- 使用多行比較操作符
3.1多行比較操作符
操作符 | 含義 |
---|---|
IN | 等于列表中的任意一個(gè) |
ANY | 需要和單行比較操作符一起使用,和子查詢返回的某一個(gè)值比較 |
ALL | 需要和單行比較操作符一起使用,和子查詢返回的所有值比較 |
SOME | 實(shí)際上是ANY的別名,作用相同,一般常使用ANY |
3.2代碼實(shí)例
SELECT employee_id, last_name FROM employees WHERE salary in (SELECT MIN(salary) FROM employees GROUP BY department_id);
返回其它job_id中比job_id為‘IT_PROG’部門任一工資低的員工的員工號(hào)、姓名、job_id 以及salary
#返回其它job_id中比job_id為‘IT_PROG'部門任一工資低的員工的員工號(hào)、姓名、job_id 以及salary SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary < ANY( SELECT salary FROM employees WHERE job_id = 'IT_PROG' ) AND job_id <> 'IT_PROG'; #返回其它job_id中比job_id為‘IT_PROG'部門所有工資低的員工的員工號(hào)、姓名、job_id 以及salary SELECT employee_id,last_name,job_id,salary FROM employees WHERE salary < ALL( SELECT salary FROM employees WHERE job_id = 'IT_PROG' ) AND job_id <> 'IT_PROG';
查詢平均工資最低的部門id
相當(dāng)于創(chuàng)建了一張臨時(shí)的表
# 聚合函數(shù)不能嵌套,單行函數(shù)才能嵌套使用 SELECT employee_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 )t_dept_avg_sal); #方式二 SELECT employee_id FROM employees GROUP BY department_id HAVING AVG(salary) <= ALL( SELECT AVG(salary) avg_sal FROM employees GROUP BY department_id );
3.3空值問(wèn)題
SELECT last_name FROM employees WHERE employee_id NOT IN ( SELECT manager_id FROM employees #where manager_id is not null );
4.相關(guān)子查詢
如果子查詢的執(zhí)行依賴于外部查詢,通常情況下都是因?yàn)樽硬樵冎械谋碛玫搅送獠康谋?,并進(jìn)行了條件關(guān)聯(lián),因此每執(zhí)行一次外部查詢,子查詢都要重新計(jì)算一次,這樣的子查詢就稱之為 關(guān)聯(lián)子查詢 .相關(guān)子查詢按照一行接一行的順序執(zhí)行,主查詢的每一行都執(zhí)行一次子查詢。
4.1代碼實(shí)例
題目:查詢員工中工資大于本部門平均工資的員工的last_name,salary和其department_id
#回顧:查詢員工中工資大于本公司平均工資的員工的last_name,salary和其department_id SELECT last_name,salary,department_id FROM employees e1 WHERE salary > ( SELECT AVG(salary) FROM employees e2 ); #題目:查詢員工中工資大于本部門平均工資的員工的last_name,salary和其department_id SELECT last_name,salary,department_id FROM employees e1 WHERE salary > ( SELECT AVG(salary) FROM employees e2 WHERE department_id = e1.`department_id` ); #方式二,在from中聲明子查詢 SELECT e.last_name,e.salary,e.department_id FROM employees e,(SELECT department_id,AVG(salary) avg_sal FROM employees GROUP BY department_id) temp WHERE e.department_id = temp.department_id AND e.salary > temp.avg_sal;
題目:查詢員工的id,salary,按照department_name 排序
SELECT employee_id,salary FROM employees e1 ORDER BY ( SELECT department_name FROM departments d WHERE e1.`department_id` = d.`department_id` );
題目:若employees表中employee_id與job_history表中employee_id相同的數(shù)目不小于2,輸出這些相同id的員工的employee_id,last_name和其job_id
#若employees表中employee_id與job_history表中employee_id相同的數(shù)目不小于2,輸出這些相同 #id的員工的employee_id,last_name和其job_id SELECT employee_id,last_name,job_id FROM employees e WHERE 2 <= (SELECT COUNT(*) FROM job_history j WHERE e.`employee_id` = j.`employee_id` );
4.2結(jié)論:
在哪里可以寫(xiě)子查詢:
在select中,除了GROUP BY 和 LIMIT之外,其他位置都可以聲明子查詢
4.3EXISTS 與 NOT EXISTS關(guān)鍵字
關(guān)聯(lián)子查詢通常也會(huì)和 EXISTS操作符一起來(lái)使用,用來(lái)檢查在子查詢中是否存在滿足條件的行。
如果在子查詢中不存在滿足條件的行:
- 條件返回 FALSE
- 繼續(xù)在子查詢中查找
如果在子查詢中存在滿足條件的行: - 不在子查詢中繼續(xù)查找
- 條件返回 TRUE
NOT EXISTS關(guān)鍵字表示如果不存在某種條件,則返回TRUE,否則返回FALSE。
題目:查詢departments表中,不存在于employees表中的部門的department_id和department_name
#方式一:自連接 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 DISTINCT manager_id FROM employees SELECT employee_id,last_name,job_id,department_id FROM employees WHERE employee_id IN ( SELECT DISTINCT manager_id FROM employees ) #方式三:exists SELECT employee_id,last_name,job_id,department_id FROM employees e1 WHERE EXISTS ( SELECT * FROM employees e2 WHERE e1.`employee_id`= e2.`manager_id` )
查詢departments表中,不存在于employees表中的部門的department_id和department_name
#方式一: SELECT d.department_id,d.department_name FROM employees e RIGHT JOIN departments d ON e.department_id = d.department_id WHERE e.department_id IS NULL; #方式二: SELECT department_id,department_name FROM departments d WHERE NOT EXISTS ( SELECT * FROM employees e WHERE d.`department_id` = e.`department_id` );
5.相關(guān)更新
UPDATE table1 alias1 SET column = (SELECT expression FROM table2 alias2 WHERE alias1.column = alias2.column);
使用相關(guān)子查詢依據(jù)一個(gè)表中的數(shù)據(jù)更新另一個(gè)表的數(shù)據(jù)。
題目:在employees中增加一個(gè)department_name字段,數(shù)據(jù)為員工對(duì)應(yī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)子查詢依據(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);
問(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:子查詢 SELECT last_name,salary FROM employees WHERE salary > ( SELECT salary FROM employees WHERE last_name = 'Abel' );
問(wèn)題:以上兩種方式有好壞之分嗎?
解答:自連接方式好!
題目中可以使用子查詢,也可以使用自連接。一般情況建議你使用自連接,因?yàn)樵谠S多 DBMS 的處理過(guò)程中,對(duì)于自連接的處理速度要比子查詢快得多。
可以這樣理解:子查詢實(shí)際上是通過(guò)未知表進(jìn)行查詢后的條件判斷,而自連接是通過(guò)已知的自身數(shù)據(jù)表進(jìn)行條件判斷,因此在大部分 DBMS 中都對(duì)自連接處理進(jìn)行了優(yōu)化。
總結(jié)
到此這篇關(guān)于MySQL子查詢?cè)斀獾奈恼戮徒榻B到這了,更多相關(guān)MySQL子查詢內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL學(xué)習(xí)筆記5:修改表(alter table)
我們?cè)趧?chuàng)建表的過(guò)程中難免會(huì)考慮不周,因此后期會(huì)修改表修改表需要用到alter table修改表語(yǔ)句,接下來(lái)詳細(xì)介紹,需要的朋友可以參考下2013-01-01MySql UNION 一行轉(zhuǎn)多列的實(shí)現(xiàn)示例
在MySQL命令行中,有時(shí)候我們會(huì)遇到一行的數(shù)據(jù)需要以多列的形式呈現(xiàn)的情況,本文就詳細(xì)介紹了一下一行轉(zhuǎn)多列的實(shí)現(xiàn)示例,具有一定的參考價(jià)值,感興趣的可以了解一下2023-08-08Winserver2012下mysql 5.7解壓版(zip)配置安裝教程詳解
這篇文章主要介紹了Winserver2012下mysql 5.7解壓版(zip)配置安裝教程詳解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-01-01Windows下MySQL5.6查找my.ini配置文件的方法
今天小編就為大家分享一篇Windows下MySQL5.6查找my.ini配置文件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-06-06mysql經(jīng)典4張表問(wèn)題詳細(xì)講解
MySQL是一種關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),可以通過(guò)連接不同的表將數(shù)據(jù)進(jìn)行關(guān)聯(lián)查詢,下面這篇文章主要給大家介紹了關(guān)于mysql經(jīng)典4張表問(wèn)題的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-03-03