1. 程式人生 > >轉!!SQL左右連接中的on and和on where的區別

轉!!SQL左右連接中的on and和on where的區別

生成 where條件 data- 一個 highlight article 根據 返回 地址

原博文地址:http://blog.csdn.net/xingzhemoluo/article/details/39677891

原先一直對SQL左右連接中的on and和on where的區別不是太了解,直到在網上看到了下面這段話才豁然開朗。

在使用left join時,on and和on where條件的區別如下:
1、on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。
2、where條件是在臨時表生成好後,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉,on後的條件用來生成左右表關聯的臨時表,where後的條件對臨時表中的記錄進行過濾。

實踐是檢驗真理的唯一標準,接下來用實驗來證明一下:

先上表結構以及數據:

[sql] view plain copy print?
  1. SQL> create table A (id int, type int);
  2. SQL> select * from A;
  3. ID TYPE
  4. ---------- ----------
  5. 1 1
  6. 2 1
  7. 3 2
  8. SQL> create table B(id int ,class int);
  9. SQL> select * from B;
  10. ID CLASS
  11. ---------- ----------
  12. 1 1
  13. 2 2

[sql] view plain copy print?
  1. SQL> select * from A left join B on A.id = B.id where A.type = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 1 1 1
  5. 2 1 2 2

根據上面那段話的解釋,where字句是在生成臨時表以後再進行過濾的,也就是可以理解為就是一個左連接:select * from A left join B on A.id = B.id;

其運行結果如下:

[sql] view plain copy print?
  1. SQL> select * from A left join B on A.id = b.id;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 1 1 1
  5. 2 1 2 2
  6. 3 2

然後加上where A.type = 1對臨時表進行過濾,除掉A.type不為1的,顯然結果正確。

[sql] view plain copy print?
  1. SQL> select * from A left join B on A.id = B.id and A.type = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 1 1 1
  5. 2 1 2 2
  6. 3 2

因為左連接不管on and語句是否為真都必須返回左表所有的記錄,所以and A.type=1;沒有起到任何作用。

[sql] view plain copy print?
  1. SQL> select * from A left join B on A.id = B.id and B.class = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 1 1 1
  5. 3 2
  6. 2 1

根據上面那段話的解釋:on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。顯然左連接再加上新的條件:B.class = 1篩選掉第二行記錄,結果正確。

[sql] view plain copy print?
  1. SQL> select * from A left join B on A.id = B.id where B.class = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 1 1 1

原因通①。(①,②)和(③,④)就是關鍵詞on and和on where的區別,但結果卻完全不同。綜上三個例子,where是生成臨時表以後再進行過濾,對左右表都進行篩選。而and後面的語句如果是對left join中的左表進行過濾將不起任何作用,對右表進行過濾的話,那麽左表還是返回所有行,只是右表會被過濾掉一部分行。

再來看看內連接inner join on and和 on where的區別:

由於剛開始表的數據不是太適合,所以先稍微更新一下,這樣更好觀察inner join和left join在and和where的不同之處。

[sql] view plain copy print?
  1. SQL> update A set type = 2 where id = 1;
  2. 已更新 1 行。
  3. SQL> select * from A;
  4. ID TYPE
  5. ---------- ----------
  6. 1 2
  7. 2 1
  8. 3 2
  9. SQL> select * from B;
  10. ID CLASS
  11. ---------- ----------
  12. 1 1
  13. 2 2

先看看and的:

[sql] view plain copy print?
  1. SQL> select * from A inner join B on A.id = B.id and A.type = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 2 1 2 2

顯然輸出結果與左連接的不一樣,先與沒有and的內連接比較一下:

[sql] view plain copy print?
  1. SQL> select * from A inner join B on A.id = B.id;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 2 1 1
  5. 2 1 2 2

顯然如果按左連接的邏輯,這個結果就是錯誤的。但這是Oracle輸出的,而不是我瞎打的,顯然在內連接時與左連接不同了。這裏on and條件和on where條件一樣對生成以後的臨時表同樣會被過濾。顯然A表id為1的type不為1,所以它被過濾了。

再上幾組來驗證一下上面這個猜想是否是正確的:

再來看看內連接的where:

[sql] view plain copy print?
  1. SQL> select * from A inner join B on A.id = B.id where A.type = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 2 1 2 2

這個也是和左連接一樣生成臨時表然後進行過濾,不作解釋。

[sql] view plain copy print?
  1. SQL> select * from A inner join B on A.id = B.id and B.class = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 2 1 1


[sql] view plain copy print?
  1. SQL> select * from A inner join B on A.id = B.id where B.class = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 2 1 1

對比發現:(⑤,⑥)和(⑦,⑧)結果都一樣,也就是說內連接inner join on and 或者on where不管是對左表還是右表進行過濾,實際都是在生成臨時表以後再進行過濾的,而且對左表和右表都起作用,這與左連接left join有本質的區別!!!

最後上倆沒有使用連接語句的例子:

[sql] view plain copy print?
  1. </pre><p></p><pre name="code" class="sql">SQL> select * from A,B where A.id = B.id and A.type = 1;
  2. ID TYPE ID CLASS
  3. ---------- ---------- ---------- ----------
  4. 1 1 1 1
  5. 2 1 2 2
  6. SQL> select * from A,B where A.type = 1 and A.id = B.id;
  7. ID TYPE ID CLASS
  8. ---------- ---------- ---------- ----------
  9. 1 1 1 1
  10. 2 1 2 2


比較簡單,不作解釋。

總結一下:

在使用left join時,on和where條件的區別如下:
1、on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。(實際上左連接中如果and語句是對左表進行過濾的,那麽不管真假都不起任何作用。如果是對右表過濾的,那麽左表所有記錄都返回,右表篩選以後再與左表連接返回)
2、where條件是在臨時表生成好後,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉,on後的條件用來生成左右表關聯的臨時表,where後的條件對臨時表中的記錄進行過濾。

在使用inner join時,不管是對左表還是右表進行篩選,on and和on where都會對生成的臨時表進行過濾。

轉!!SQL左右連接中的on and和on where的區別