在開始分析之前,我們先準備一些測試數據。首先,初始化三張表,分別爲test_user,test_team,test_type,建表語句如下
create table TEST_USER
(
user_id NUMBER,
user_name VARCHAR2(30 CHAR),
user_team NUMBER,
user_type VARCHAR2(30 CHAR)
);
create table test_team(
team_id number,
team_name varchar2(30char)
);
create table test_type(
type_id number,
type_name varchar2(30char)
);
初始化數據
insert into TEST_USER (USER_ID, USER_NAME, USER_TEAM, USER_TYPE)
values (1, 'user1', 1, '1');
insert into TEST_USER (USER_ID, USER_NAME, USER_TEAM, USER_TYPE)
values (2, 'user2', 2, null);
insert into TEST_USER (USER_ID, USER_NAME, USER_TEAM, USER_TYPE)
values (3, 'user3', 5, '2');
insert into TEST_USER (USER_ID, USER_NAME, USER_TEAM, USER_TYPE)
values (4, 'user4', null, '3');
insert into TEST_USER (USER_ID, USER_NAME, USER_TEAM, USER_TYPE)
values (5, 'user5', 3, '6');
insert into TEST_TEAM (TEAM_ID, TEAM_NAME)
values (1, 'team1');
insert into TEST_TEAM (TEAM_ID, TEAM_NAME)
values (2, 'team2');
insert into TEST_TEAM (TEAM_ID, TEAM_NAME)
values (3, 'team3');
insert into TEST_TEAM (TEAM_ID, TEAM_NAME)
values (4, 'team4');
insert into TEST_TYPE (TYPE_ID, TYPE_NAME)
values (1, 'type1');
insert into TEST_TYPE (TYPE_ID, TYPE_NAME)
values (2, 'type2');
insert into TEST_TYPE (TYPE_ID, TYPE_NAME)
values (3, 'type3');
三張表的數據,如下表格
表:test_user
USER_ID | USER_NAME | USER_TEAM | USER_TYPE |
---|---|---|---|
1 | user1 | 1 | 1 |
2 | user2 | 2 | |
3 | user3 | 5 | 2 |
4 | user4 | 3 | |
5 | user5 | 3 | 6 |
TEAM_ID | TEAM_NAME |
---|---|
1 | team1 |
2 | team2 |
3 | team3 |
4 | team4 |
表:test_type
TYPE_ID | TYPE_NAME |
---|---|
1 | type1 |
2 | type2 |
3 | type3 |
一、左連接 left join
左連接是把left join左邊表的數據都查詢出來,具體用法,比如
select * from test_user a left join test_team b on a.user_team=b.team_id
查詢結果如下
這裏left join語句中左側表,即test_user表所有記錄都會查詢出來,on關鍵字後面跟的關聯條件應理解爲匹配條件,對於left join右側的表,即test_team表滿足匹配條件的,顯示對應右側表的記錄信息,不滿足匹配條件右側表對應字段的記錄顯示爲NULL。
下面我們再來看一個sql
select * from test_user a left join test_team b on a.user_team=b.team_id and b.team_id=1
查詢結果如下
通過上述的描述可知,表test_user和test_team滿足a.user_team=b.team_id and b.team_id=1匹配條件的只有第一條記錄
其他不滿足匹配條件的test_team對應字段顯示爲NULL.
我們繼續查詢一個sql
select * from test_user a left join test_team b on a.user_team=b.team_id and a.user_id=2
查詢結果如下
同上,表test_user和test_team滿足a.user_team=b.team_id and a.user_id=2匹配條件的只有第一條記錄,其他不滿足匹配條件的test_team對應字段顯示爲NULL.
關於on條件與where的區別
我們將sql
select * from test_user a left join test_team b on a.user_team=b.team_id and b.team_id=1
中的and該爲where
select * from test_user a left join test_team b on a.user_team=b.team_id where b.team_id=1
查詢結果如下
這裏的where應理解過濾條件,查詢是會先按on後的匹配條件a.user_team=b.team_id形成符合要求的臨時表,然後where後面的條件b.team_id=1剔除不符合條件的記錄。
同理,另一個改寫的sql
select * from test_user a left join test_team b on a.user_team=b.team_id where a.user_id=2
查詢結果如下
oracle中的(+)
在oracle中左連接left join可以用左連接的表,在其關聯關係一側加(+)表示,
比如左連接sql
select * from test_user a left join test_team b on a.user_team=b.team_id
改寫成(+)形式,有如下兩種方式,效果是一樣的
select * from test_user a,test_team b where a.user_team=b.team_id(+);
或者
select * from test_user a,test_team b where b.team_id(+)=a.user_team;
oracle中left join和用(+)表達的方式在執行上性能是一樣的。對應的執行計劃分別如下:
和
這裏還有個值得注意的地方,如若sql
select * from test_user a left join test_team b on a.user_team=b.team_id and b.team_id=1
改寫成(+)該如何改寫呢?
這樣嗎?
這樣改寫是錯的,從查詢結果就可以看出來。因爲where後跟的是過濾條件,在
select * from test_user a left join test_team b on a.user_team=b.team_id and b.team_id=1
中b.team_id=1在on後面作爲匹配條件,不影響結果返回的條數,不會根據條件對結果進行剔除。這裏將b.team_id=1放在where是過濾條件。
正確的改寫方式,應按照上面的強調的 左連接left join可以用左連接的表,在其關聯關係一側加(+)表示(其實右連接right join也一樣),即改寫如下
select * from test_user a,test_team b where a.user_team=b.team_id(+) and b.team_id(+)=1;
查詢結果如下
二、右連接 right join
右連接是把right join左邊表的數據都查詢出來,具體用法,比如
select * from test_type a right join test_user b on a.type_id=b.user_type
查詢結果如下
這裏right join語句中右側表,即test_user表所有記錄都會查詢出來,on關鍵字後面跟的關聯條件應理解爲匹配條件,對於right join左側的表,即test_type表滿足匹配條件的,顯
示對應右側表的記錄信息,不滿足匹配條件左側表對應字段的記錄顯示爲NULL。
對於right join可以類比left join來看,包括在oracle用(+)來進行改寫,只不過(+)要加在right join左側表在關聯關係中的一側。
三、內連接inner join
如果說right join,left join是拿一張表去匹配另一張表,匹配上信息對應信息,否則返回NULL,而內連接呢相當於兩張表相互匹配,取其交集。即相當於where後的=連接。
所以下方兩個sql是等效的。
和