left/right join中on和where的區別
- 2020 年 3 月 18 日
- 筆記
開發同學提了個問題,如下兩種left join中on和where條件的寫法是否等價?
select * from j_a left join j_b on j_a.id=j_b.id where j_a.name='b'; select * from j_a left join j_b on j_a.id=j_b.id and j_a.name='b';
我們先看測試,創建兩張測試表,導入一些數據,
SQL> create table j_a(id number, name varchar2(1)); Table created. SQL> create table j_b(id number, name varchar2(1)); Table created. SQL> select * from j_a; ID N ---------- - 1 a 2 b 3 c SQL> select * from j_b; ID N ---------- - 2 d 3 e 5 o
為了比較,先看下join全連接,共有2條記錄,
SQL> select * from j_a join j_b on j_a.id=j_b.id; ID N ID N ---------- - ---------- - 2 b 2 d 3 c 3 e
使用left join,會顯示j_a表的3條記錄,其中j_a.id=1的記錄,對應j_b為空,
SQL> select * from j_a left join j_b on j_a.id=j_b.id; ID N ID N ---------- - ---------- - 2 b 2 d 3 c 3 e 1 a
使用on,得到3條記錄,
SQL> select * from j_a left join j_b on j_a.id=j_b.id and j_a.name='b'; ID N ID N ---------- - ---------- - 2 b 2 d 3 c 1 a
使用where,得到1條記錄,
SQL> select * from j_a left join j_b on j_a.id=j_b.id where j_a.name='b'; ID N ID N ---------- - ---------- - 2 b 2 d
從測試結論看,left join使用on和where得到的結果集是不相同的。
究其原因,是兩種關鍵字執行的時間點有所區別。
(1) on條件是在left join生成臨時表時執行的,因此無論on中的條件是否為真,都會返回左邊表中的所有記錄,所以上述測試中,得到3條記錄。
(2) where條件是在left join臨時表生成後,再對臨時表進行過濾,此時是沒有left join的含義了,條件不為真的就會被過濾,所以上述測試中,得到1條記錄。
因此,之所以on和where的測試結果不同,這和left join、right join的特性是有關的,因為on的條件無論是否為真,都會返回left或right表中的記錄。
當然,非得用這種寫法,使用is not null,還是能讓on和where得到相同的結果集,
select * from j_a left join j_b on j_a.id=j_b.id and j_a.name='b' and j_b.id is not null;
如果是join/full join,他是left join和right join的並集,所以使用on和where是相同的結果。
使用join和on,得到1條記錄,
SQL> select * from j_a join j_b on j_a.id=j_b.id and j_a.name='b'; ID N ID N ---------- - ---------- - 2 b 2 d
這是使用join和where,得到1條記錄,
SQL> select * from j_a join j_b on j_a.id=j_b.id where j_a.name='b'; ID N ID N ---------- - ---------- - 2 b 2 d
對待問題,從原理的理解,加上實際的測試,才可能讓你抓到問題的本質,才可能讓他成為你真正掌握的知識。不僅是Oracle,還是其他的技術,又或是任何其他的領域,都是如此。