1. 程式人生 > >一步一步學MySQL----16 多表資料記錄查詢之子查詢

一步一步學MySQL----16 多表資料記錄查詢之子查詢

16.1 為什麼使用子查詢

日常工作中,經常會用到多表查詢,而在進行多表查詢時,首先會對兩個表進行笛卡爾積操作,然後再選取符合匹配條件的資料記錄。在進行笛卡爾積操作的時候,會生成兩個資料表中資料記錄數的乘積條資料記錄。如果這兩個表的資料記錄比較大,則在進行笛卡爾積操作時就會造成宕機。


因此,對於有經驗的使用者,首先會通過統計函式檢視所操作笛卡爾積後的資料記錄數,然後才會進行多表查詢。

因此,多表查詢的一般步驟如下:

(1) 通過統計函式count()查詢笛卡爾積後的資料記錄數,如:

mysql> select count(*)

from employee e, department d;

(2) 如果查詢到的資料記錄MySQL可接受,然後才進行多表查詢,否則就應該考慮其他方式來實現。

針對笛卡爾積後的資料記錄數遠遠大於MySQL可以接受的範圍這個問題,MySQL提供了子查詢操作來解決這個問題。

所謂子查詢,就是指在一個查詢語句中嵌套了其他的若干查詢,即在一個select查詢語句的where或from子句中包含另一個select查詢語句。

在查詢語句中,外層select查詢語句稱為主查詢,where子句中的select查詢語句稱為子查詢,也被稱之為巢狀查詢。

通過子查詢可以實現多表查詢,該查詢語句中可能包含in

anyallexists等關鍵字,除此之外還可能包含比較運算子。

理論上,子查詢語句可以出現在查詢語句的任何位置,但是實際應用中,子查詢經常出現在where和from子句中。

  • Where子句中的子查詢:該位置處的子查詢一般返回單行單列、多行單列、單行多列資料記錄

  • From子句中的子查詢:該位置處的子查詢一般返回多行多列資料記錄,可以當作一張臨時表。

16.2 單行單列的子查詢

說明:當子查詢的返回結果為單行單列的資料記錄時,該子查詢語句一般在祝查詢語句的where子句中,通常包含比較運算子(“>”、“<”、“=”、“!=”等)

例如:執行SQL查詢語句,在資料庫company中,查詢員工表中工資比Smith還要高的全部員工資訊。

第一步:查詢Smith員工的工資

mysql> select salary from employee where ename=”Smith”;

這裡寫圖片描述

第二步:由於上述SQL語句返回單行單列,所以可以在主查詢where關鍵字子句中出現

mysql> select * from employee where salary>(select salary from employee where ename=”Smith”);

這裡寫圖片描述

16.3 單行多列的子查詢

例如:執行SQL查詢語句,在資料庫company中,查詢員工表中與James所在同一部門並且工資比James高的所有員工的資訊。

第一步:查詢James所在部門和工資

mysql> select depno,salary from employee where ename=”James”

這裡寫圖片描述

第二步:由於上述SQL語句返回單行多列,所以可以在主查詢的where子句中出現。

mysql> select * from employee where depno=(select depno from employee where ename=”james”) and salary>(select salary from employee where ename=”james”);

這裡寫圖片描述

16.4 多行單列帶有in的子查詢

當主查詢的條件是子查詢的查詢結果時,就可以通過關鍵字in來進行判斷。相反,當主查詢的條件不是子查詢的查詢結果時,就可以通過關鍵字not in來進行判斷。

例如:執行SQL查詢語句,在資料庫company中,查詢員工表中的資料記錄,這些記錄的部門編號必須在部門表中出現。

第一步:查詢部門表的所有部門編號。

mysql> select depno from department;

這裡寫圖片描述

第二步:由於上述語句返回的是多行單列,所以可以在主查詢的where子句中出現。

mysql> select * from employee where depno in(select depno from department);

這裡寫圖片描述

由於員工Kuli所在的部門不在部門表中,如果要通過子查詢來查詢其員工資訊,如下:

mysql> select * from employee where depno not in(select depno from department);

這裡寫圖片描述

16.5 多行單列帶有any的子查詢

關鍵字 any用來表示主查詢的條件為滿足子查詢返回查詢結果中任意一條資料記錄,該關鍵字有三種匹配方式:

  • =any:其功能與in一樣
  • >any(>=any):比子查詢中返回的資料記錄中最小的還要大於(大於等於)的資料記錄
  • < any(<=any):比子查詢中返回的資料記錄中最大的還要小於(小於等於)的資料記錄

例如:執行SQL查詢語句,在資料庫company中,查詢員工表中員工的姓名和工資,這些員工的工資不低於工種為Developer的工資

第一步:查詢員工表中工種為Developer的工資

mysql> select salary from employee where job=”Developer”;

這裡寫圖片描述

第二步:由於上述語句是多行單列,所以可以在主查詢的where關鍵字子句中出現

mysql> select ename,salary from employee where salary>any(select salary from employee where job=”Developer”);

這裡寫圖片描述

16.6 多行單列帶有all的子查詢

關鍵字all用來表示主查詢的條件滿足子查詢返回查詢結果中所有資料記錄,該關鍵字有以下兩種匹配方式:

  • >all(>=all):比子查詢中返回資料記錄中最大的還要大於(大於等於)資料記錄;
  • < all(<=all):比子查詢中返回資料記錄中最小的還要小於(小於等於)資料記錄;

例如:執行SQL查詢語句,在資料庫company中,查詢員工表中的員工的姓名和工資,這些員工的工資高於工種為Developer的工資

第一步:查詢員工表中工種為Developer的工資

mysql> select salary from employee where job=”Developer”;

這裡寫圖片描述

第二步:由於上述語句是多行單列,所以可以在主查詢的where關鍵字子句中出現

mysql> select ename,salary from employee where salary>all(select salary from employee where job=”Developer”);

這裡寫圖片描述

16.7 多行單列帶有exists的子查詢

關鍵字exists是一個布林型別,當返回結果集時為true,不能返回結果集時為false。

查詢時,exists對外表採用遍歷方式逐條查詢,每次查詢都會比較exists的條件語句,當exists裡的條件語句返回記錄時則條件為真,此時返回當前遍歷到的記錄;反之,如果exists裡的條件語句不能返回記錄時,則丟棄當前遍歷到的記錄。

例如:執行SQL查詢語句,在資料庫company中,查詢部門表中的部門編號和部門名字,如果該部門沒有員工,則顯示該部門。

第一步:查詢員工表和部門表,條件為員工表中的部門編號等於部門表中的部門編號

mysql> select * from employee e, department d where e.depno=d.depno;

這裡寫圖片描述

第二步:查詢有員工的部門編號和名稱

mysql> select depno,dname from department d where exists(select * from employee e where e.depno=d.depno);

這裡寫圖片描述

16.8 多行多列的子查詢

當子查詢的返回結果為多行多列資料記錄時,該子查詢語句一般會在主查詢語句的from子句中,被當作一張臨時表的方式來處理。

例如:執行SQL語句select,在資料庫company中,查詢員工表中各個部門的部門編號、部門名稱、部門地址、員工人數和平均工資。

方法1:通過內連線來實現

mysql> select d.depno,d.dname,d.location,count(e.ename) number, avg(e.salary) average_salary from employee e inner join department d on e.depno=d.depno group by d.depno desc;

這裡寫圖片描述

在執行過程中,關於笛卡爾積的資料記錄數,可以通過以下SQL語句來查詢

mysql> select count(*) from employee,department;

這裡寫圖片描述

方法2:通過子查詢來實現

mysql> select d.depno,d.dname,d.location,number,average_salary from department d inner join(select depno, count(empno) number, avg(salary) average_salary from employee e group by depno desc) e on d.depno=e.depno;

這裡寫圖片描述

在執行過程中,關於笛卡爾積的資料記錄數,可以通過以下SQL語句來查詢

mysql> select count(*) from department,(select depno, count(empno) number, avg(salary) average_salary from employee group by depno) employee;

這裡寫圖片描述

與內連線方式查詢相比,子查詢方式所操作的笛卡爾積資料記錄遠遠小於前者,因此子查詢方式的執行效率更高。