一、基本邏輯
對於外部查詢返回的每一行數據,內部查詢都要執行一次。在關聯子查詢中是信息流是雙向的。外部查詢的每行數據傳遞一個值給子查詢,然后子查詢為每一行數據執行一次並返回它的記錄。然后,外部查詢根據返回的記錄做出決策。
反正我是沒看懂,下面詳細解釋SQL中關聯子查詢的邏輯。
二、舉例
員工表的主要信息:
要解決的問題:檢索工資大於同職位的平均工資的員工信息。
2.1 直覺的做法
員工多,而相應的職位(如銷售員、經理、部門經理等)少,因此首先想到的思路是對職位分組,這樣就能分別得到各個職位的平均工資,再比較每個人的工資和他對應職位的平均工資,大於則被篩選出來。
首先得到各個職位的平均工資
代碼如下:
1 select job,avg(sal) from emp 2 group by job;
結果如下:
然后利用子查詢,對他們進行對比(幻想)
代碼如下:
1 select * from emp where sal > 2 (select avg(sal) from emp 3 group by job);
但是子表查詢結果是5行,因此這段代碼根本無法執行。
2.2 正確的做法
正確的做法是使用關聯子查詢。代碼如下。
1 select * from emp e where sal > 2 (select avg(sal) from emp where job = e.job);
執行邏輯是這樣
第一步
先執行外層查詢,即先執行:
1 select * from emp e;
結果是:
也就是該表的所有內容。又因為子查詢中連接了這個表本身(where job = e.job ),所以將第一條記錄轉到子查詢。
第二步
這條進入子查詢后,子查詢job是CLERK,所以先篩選出所有Job=‘CLERK’的,再對他們取平均。
相當於執行了:
1 select avg(sal) from emp where job='CLERK';
結果是
第三步
這個結果進入外層查詢where和SMITH這個人的sal進行對比,相當於執行了
select * from emp where sal>1037.5 and job='CLERK';
結果是為:
循環
然后就抽出第一次外層查詢的第二條(ALLEN):
繼續如上第一、二、三部。
重復計算嗎?
每條記錄都執行,第二行的ALLEN和第三行的WARD都是SALESMAN(銷售人員),那么他們在子查詢中會重復計算一次平均工資進行比較。這樣會不會設計重復計算?答案是不會,效率並沒有降低,SQL已經對此進行過優化。