語法
join 用於根據兩個或多個表中的列之間的關系,從這些表中查詢數據。
Join 和 Key
有時為了得到完整的結果,我們需要從兩個或更多的表中獲取結果。我們就需要執行 join。
數據庫中的表可通過鍵將彼此聯系起來。主鍵(Primary Key)是一個列,在這個列中的每一行的值都是唯一的。在表中,每個主鍵的值都是唯一的。這樣做的目的是在不重復每個表中的所有數據的情況下,把表間的數據交叉捆綁在一起。
請看 "Persons" 表:
Id_P | LastName | FirstName | Address | City |
---|---|---|---|---|
1 | Adams | John | Oxford Street | London |
2 | Bush | George | Fifth Avenue | New York |
3 | Carter | Thomas | Changan Street | Beijing |
請注意,"Id_P" 列是 Persons 表中的的主鍵。這意味着沒有兩行能夠擁有相同的 Id_P。即使兩個人的姓名完全相同,Id_P 也可以區分他們。
接下來請看 "Orders" 表:
Id_O | OrderNo | Id_P |
---|---|---|
1 | 77895 | 3 |
2 | 44678 | 3 |
3 | 22456 | 1 |
4 | 24562 | 1 |
5 | 34764 | 65 |
請注意,"Id_O" 列是 Orders 表中的的主鍵,同時,"Orders" 表中的 "Id_P" 列用於引用 "Persons" 表中的人,而無需使用他們的確切姓名。
請留意,"Id_P" 列把上面的兩個表聯系了起來。
引用兩個表
我們可以通過引用兩個表的方式,從兩個表中獲取數據:
誰訂購了產品,並且他們訂購了什么產品?
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons, Orders WHERE Persons.Id_P = Orders.Id_P
結果集:
LastName | FirstName | OrderNo |
---|---|---|
Adams | John | 22456 |
Adams | John | 24562 |
Carter | Thomas | 77895 |
Carter | Thomas | 44678 |
SQL JOIN - 使用 Join
除了上面的方法,我們也可以使用關鍵詞 JOIN 來從兩個表中獲取數據。
如果我們希望列出所有人的定購,可以使用下面的 SELECT 語句:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo
FROM Persons
INNER JOIN Orders
ON Persons.Id_P = Orders.Id_P
ORDER BY Persons.LastName
結果集:
LastName | FirstName | OrderNo |
---|---|---|
Adams | John | 22456 |
Adams | John | 24562 |
Carter | Thomas | 77895 |
Carter | Thomas | 44678 |
不同的 SQL JOIN
除了我們在上面的例子中使用的 INNER JOIN(內連接),我們還可以使用其他幾種連接。
下面列出了您可以使用的 JOIN 類型,以及它們之間的差異。
- JOIN: 如果表中有至少一個匹配,則返回行
- LEFT JOIN: 即使右表中沒有匹配,也從左表返回所有的行
- RIGHT JOIN: 即使左表中沒有匹配,也從右表返回所有的行
- FULL JOIN: 只要其中一個表中存在匹配,就返回行
之前例子是inner join 現在展示 left join 和 full join
left join
"Persons" 表:
Id_P | LastName | FirstName | Address | City |
---|---|---|---|---|
1 | Adams | John | Oxford Street | London |
2 | Bush | George | Fifth Avenue | New York |
3 | Carter | Thomas | Changan Street | Beijing |
"Orders" 表:
Id_O | OrderNo | Id_P |
---|---|---|
1 | 77895 | 3 |
2 | 44678 | 3 |
3 | 22456 | 1 |
4 | 24562 | 1 |
5 | 34764 | 65 |
左連接(LEFT JOIN)實例
現在,我們希望列出所有的人,以及他們的定購 - 如果有的話。
您可以使用下面的 SELECT 語句:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons LEFT JOIN Orders ON Persons.Id_P=Orders.Id_P ORDER BY Persons.LastName
結果集:
LastName | FirstName | OrderNo |
---|---|---|
Adams | John | 22456 |
Adams | John | 24562 |
Carter | Thomas | 77895 |
Carter | Thomas | 44678 |
Bush | George |
LEFT JOIN 關鍵字會從左表 (Persons) 那里返回所有的行,即使在右表 (Orders) 中沒有匹配的行。
full join
原始的表 (用在例子中的):
"Persons" 表:
Id_P | LastName | FirstName | Address | City |
---|---|---|---|---|
1 | Adams | John | Oxford Street | London |
2 | Bush | George | Fifth Avenue | New York |
3 | Carter | Thomas | Changan Street | Beijing |
"Orders" 表:
Id_O | OrderNo | Id_P |
---|---|---|
1 | 77895 | 3 |
2 | 44678 | 3 |
3 | 22456 | 1 |
4 | 24562 | 1 |
5 | 34764 | 65 |
全連接(FULL JOIN)實例
現在,我們希望列出所有的人,以及他們的定單,以及所有的定單,以及定購它們的人。
您可以使用下面的 SELECT 語句:
SELECT Persons.LastName, Persons.FirstName, Orders.OrderNo FROM Persons FULL JOIN Orders ON Persons.Id_P=Orders.Id_P ORDER BY Persons.LastName
結果集:
LastName | FirstName | OrderNo |
---|---|---|
Adams | John | 22456 |
Adams | John | 24562 |
Carter | Thomas | 77895 |
Carter | Thomas | 44678 |
Bush | George | |
34764 |
FULL JOIN 關鍵字會從左表 (Persons) 和右表 (Orders) 那里返回所有的行。如果 "Persons" 中的行在表 "Orders" 中沒有匹配,或者如果 "Orders" 中的行在表 "Persons" 中沒有匹配,這些行同樣會列出。
join 中的 where 和 and 區別
在使用left join時,on and和on where條件的區別如下:
1、on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。
2、where條件是在臨時表生成好后,再對臨時表進行過濾的條件。這時已經沒有left join的含義(必須返回左邊表的記錄)了,條件不為真的就全部過濾掉,on后的條件用來生成左右表關聯的臨時表,where后的條件對臨時表中的記錄進行過濾。
表結構
SQL> create table A (id int, type int);
SQL> select * from A;
ID TYPE
---------- ----------
1 1
2 1
3 2
SQL> create table B(id int ,class int);
SQL> select * from B;
ID CLASS
---------- ----------
1 1
2 2
不使用條件
SQL> select * from A left join B on A.id = b.id;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
2 1 2 2
3 2
使用條件where
SQL> select * from A left join B on A.id = B.id where A.type = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
2 1 2 2
根據上面那段話的解釋,where字句是在生成臨時表以后再進行過濾的,也就是可以理解為就是一個左連接:select * from A left join B on A.id = B.id,然后加上where A.type = 1對臨時表進行過濾,除掉A.type不為1的數據。
使用and
SQL> select * from A left join B on A.id = B.id and A.type = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
2 1 2 2
3 2
因為左連接不管on and語句是否為真都必須返回左表所有的記錄,所以and A.type=1;沒有起到任何作用。
SQL> select * from A left join B on A.id = B.id and B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
3 2
2 1
根據上面那段話的解釋:on條件是在生成臨時表時使用的條件,它不管on中的條件是否為真,都會返回左邊表中的記錄。顯然左連接再加上新的條件:B.class = 1篩選掉第二行記錄,結果正確。
SQL> select * from A left join B on A.id = B.id where B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 1 1 1
where是生成臨時表以后再進行過濾,對左右表都進行篩選。如果是and,先不管過濾規則,先把左邊表數據全部返回,然戶過濾規則只對右表產生過濾。
再來看看內連接inner join on and和 on where的區別:
在使用inner join時,不管是對左表還是右表進行篩選,on and和on where都會對生成的臨時表左右兩邊同時進行過濾。
表結構
SQL> select * from A;
ID TYPE
---------- ----------
1 2
2 1
3 2
SQL> select * from B;
ID CLASS
---------- ----------
1 1
2 2
inner join 的特性就是只返回有匹配的
SQL> select * from A inner join B on A.id = B.id;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 2 1 1
2 1 2 2
SQL> select * from A inner join B on A.id = B.id where A.type = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
2 1 2 2
SQL> select * from A inner join B on A.id = B.id and B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 2 1 1
SQL> select * from A inner join B on A.id = B.id where B.class = 1;
ID TYPE ID CLASS
---------- ---------- ---------- ----------
1 2 1 1
發現會對左右兩邊同時過濾。
個人使用join和單純使用where關聯表查詢
個人測試兩個oracle語句
select r.role from user_role ur,Shiro_Role r,shiro_user su where r.id = ur.role_id and ur.user_id = su.id and su.username='cheng'
select r.role from Shiro_Role r inner join user_role ur on ur.role_id = r.id inner join shiro_user su on su.id = ur.user_id and su.username='cheng';
不使用join第一次查詢為0.329 重復查詢后為0.042到0.026
使用join第一次查詢為0.042 重復后為0.042到0.005