我們先來看一下SQL關聯子查詢的基本邏輯的定義
對於外部查詢返回的每一行數據,內部查詢都要執行一次。在關聯子查詢中是信息流是雙向的。外部查詢的每行數據傳遞一個值給子查詢,然後子查詢爲每一行數據執行一次並返回它的記錄。然後,外部查詢根據返回的記錄做出決策。
是不是沒看懂,下面詳細解釋SQL中關聯子查詢的邏輯。
有一張員工表,它的主要信息爲:
要解決的問題:檢索工資大於同職位的平均工資的員工信息。
一般我們會這樣想:
員工多,而相應的職位(如銷售員、經理、部門經理等)少,因此首先想到的思路是對職位分組,這樣就能分別得到各個職位的平均工資,再比較每個人的工資和他對應職位的平均工資,大於則被篩選出來。
首先得到各個職位的平均工資
代碼如下:
1 select job,avg(sal) from emp
2 group by job;
結果如下:
然後利用子查詢,對他們進行對比(幻想)
代碼如下
select * from emp where sal >
(select avg(sal) from emp
group by job);:
但是子表查詢結果是5行,因此這段代碼根本無法執行。
正確的做法應該是用關聯子查詢
select * from emp e where sal >
(select avg(sal) from emp where job = e.job);
第一步
先執行外層查詢,即先執行:
select * from emp e;
也就是該表的所有內容。又因爲子查詢中連接了這個表本身(where job = e.job ),所以將第一條記錄轉到子查詢。
第二步
這條進入子查詢後,子查詢job是CLERK,所以先篩選出所有Job=‘CLERK’的,再對他們取平均。
相當於執行了:
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已經對此進行過優化。