ORACLE的SQL JOIN方式大全
在ORACLE數據庫中,表與表之間的SQL JOIN方式有多種(不僅表與表,還可以表與視圖、物化視圖等聯結),官方的解釋如下所示
A join is a query that combines rows from two or more tables, views, or materialized views. Oracle Database performs a join whenever multiple tables appear in the FROM clause of the query. The select list of the query can select any columns from any of these tables. If any two of these tables have a column name in common, then you must qualify all references to these columns throughout the query with table names to avoid ambiguity.
SQL JOIN 歸納起來有下面幾種方式,下面一起來梳理一下這些概念。SQL JOIN其實是一個邏輯概念,像NEST LOOP JOIN、 HASH JOIN等是表連接的物理實現方式。
我們先准備一個兩個測試表A與B(僅僅是為了演示需要),如下腳本所示
SQL> create table A
2 (
3 name varchar2(12),
4 sex varchar2(6)
5 );
表已創建。
SQL> create table B
2 (
3 name varchar2(12),
4 grade number
5 );
表已創建。
SQL> INSERT INTO A
2 SELECT 'kerry', 'male' FROM DUAL UNION ALL
3 SELECT 'jimmy', 'male' FROM DUAL UNION ALL
4 SELECT 'tina' , 'female' FROM DUAL UNION ALL
5 SELECT 'wendy', 'female' FROM DUAL;
已創建4行。
SQL> INSERT INTO B
2 SELECT 'kerry', 3 FROM DUAL UNION ALL
3 SELECT 'jimmy', 2 FROM DUAL UNION ALL
4 SELECT 'ken' , 6 FROM DUAL UNION ALL
5 SELECT 'richard',5 FROM DUAL;
已創建4行。
SQL> commit;
提交完成。
內連接:INNER JOIN
INNER JOIN 它表示返回兩個表或記錄集連接字段的匹配記錄。如下所示,INNER JOIN 可以有二種實現方式:
SQL> select a.name,a.sex,b.grade
2 from a inner join b on a.name = b.name;
NAME SEX GRADE
------------------------ ------------ ----------
kerry male 3
jimmy male 2
SQL> select a.name,a.sex,b.grade
2 from a,b
3 where a.name = b.name;
NAME SEX GRADE
------------------------ ------------ ----------
kerry male 3
jimmy male 2
注意,INNER JOIN可以用使用簡寫JOIN方式,如下所示,但是建議使用INNER JOIN 而不是JOIN這樣的語法。
SQL> SELECT A.NAME, A.SEX,B.GRADE
2 FROM A JOIN B ON A.NAME =B.NAME;
NAME SEX GRADE
------------------------ ------------ ----------
KERRY MALE 3
jimmy male 2
多表內連接:
select *
from (odrm a
inner join custom b on a.fact_no = b.fact_no and a.custom_no = b.custom_no)
inner join stylem c on a.fact_no = c.fact_no and a.style_no = c.style_no;
如果我們用韋恩圖來解釋INNER JOIN,則非常一目了然、形象生動。可以用下面圖來表示
外連接:OUTER JOIN
1 全連接:full join
全連接 :包含左、右兩個表的全部行,不管另外一邊的表中是否存在與它們匹配的行。不符合條件的,以空值代替。如下所示:
SQL> SELECT a.NAME, b.NAME, a.SEX, b.GRADE
2 FROM a FULL OUTER JOIN b ON a.NAME=b.NAME;
NAME NAME SEX GRADE
------------------------ ------------------------ ------------ ----------
kerry kerry male 3
jimmy jimmy male 2
tina female
wendy female
ken 6
richard 5
已選擇6行。
FULL OUTER JOIN的韋恩圖如下所示:
2 左外連接:LEFT JOIN
左外連接又叫左連接 :意思是包含左邊表所有記錄,右邊所有的匹配的記錄,如果沒有則用空補齊。換句話說就是,列出左邊表全部的,及右邊表符合條件的,不符合條件的以空值代替。
SQL> SELECT a.NAME, b.NAME, a.SEX, b.GRADE
2 FROM a LEFT OUTER JOIN b ON a.NAME=b.NAME;
NAME NAME SEX GRADE
------------------------ ------------------------ ------------ ----------
kerry kerry male 3
jimmy jimmy male 2
tina female
WENDY FEMALE
SQL> SELECT a.NAME, b.NAME, a.SEX, b.GRADE
2 FROM A LEFT JOIN B ON A.NAME=B.NAME;
NAME NAME SEX GRADE
------------------------ ------------------------ ------------ ----------
kerry kerry male 3
jimmy jimmy male 2
TINA FEMALE
wendy female
多表左外連接:
select *
from (odrm a
left outer join custom b on a.fact_no = b.fact_no and a.custom_no = b.custom_no)
left outer join stylem c on a.fact_no = c.fact_no and a.style_no = c.style_no;
在ORACLE 9i以及之前,使用在(+)來表示左連接,哪個帶(+)哪個需要條件符合的,另一個全部的。即放左表示右連接,放右表示左連接。
SQL> SELECT A.NAME, B.NAME, A.SEX, B.GRADE
2 FROM A ,B
3 where a.name = b.name(+);
NAME NAME SEX GRADE
------------------------ ------------------------ ------------ ----------
kerry kerry male 3
jimmy jimmy male 2
tina female
wendy female
SQL>
3 右外連接:RIGHT JOIN
右外連接又叫右連接: 意思是包括右邊表所有記錄,匹配左邊表的記錄,如果沒有則以空補齊,換句話說,與左連接一樣,列出右邊表全部的,及左邊表符合條件的,不符合條件的用空值替代。如下所示
SQL> SELECT A.NAME, B.NAME, A.SEX, B.GRADE
2 FROM A RIGHT outer join B ON A.NAME=B.NAME;
NAME NAME SEX GRADE
------------------------ ------------------------ ------------ ----------
kerry kerry male 3
jimmy jimmy male 2
ken 6
richard 5
SQL> SELECT A.NAME, B.NAME, A.SEX, B.GRADE
2 FROM A RIGHT JOIN B ON A.NAME=B.NAME;
NAME NAME SEX GRADE
------------------------ ------------------------ ------------ ----------
kerry kerry male 3
jimmy jimmy male 2
ken 6
richard 5
SQL> SELECT A.NAME, B.NAME, A.SEX, B.GRADE
2 FROM A ,B
3 where a.name(+) = b.name;
NAME NAME SEX GRADE
------------------------ ------------------------ ------------ ----------
kerry kerry male 3
jimmy jimmy male 2
ken 6
RICHARD 5
多表右外連接:
select *
from (odrm a
right join custom b on a.fact_no = b.fact_no and a.custom_no = b.custom_no)
right join stylem c on a.fact_no = c.fact_no and a.style_no = c.style_no;
笛卡爾積:CROSS JOIN
CROSS JOIN就是笛卡爾乘積連接,不需要任何關聯條件,實現A*B的結果集,其實這種SQL JOIN方式基本上只在理論上有意義,實際當中,很少有用的CORSS JOIN方式。
注意: cross join跟inner join、outer join等有所不同,不需要關鍵詞on,因為它不需要相關字段做關聯。
SQL> SELECT a.NAME, a.SEX, b.NAME,b.GRADE
2 FROM A CROSS JOIN B;
NAME SEX NAME GRADE
------------------------ ------------ ------------------------ ----------
kerry male kerry 3
kerry male jimmy 2
kerry male ken 6
kerry male richard 5
jimmy male kerry 3
jimmy male jimmy 2
jimmy male ken 6
jimmy male richard 5
tina female kerry 3
tina female jimmy 2
tina female ken 6
NAME SEX NAME GRADE
------------------------ ------------ ------------------------ ----------
tina female richard 5
wendy female kerry 3
wendy female jimmy 2
wendy female ken 6
wendy female richard 5
已選擇16行。
SQL> SELECT A.NAME, A.SEX, B.NAME,B.GRADE
2 FROM a , b;
NAME SEX NAME GRADE
------------------------ ------------ ------------------------ ----------
kerry male kerry 3
kerry male jimmy 2
kerry male ken 6
kerry male richard 5
jimmy male kerry 3
jimmy male jimmy 2
jimmy male ken 6
jimmy male richard 5
tina female kerry 3
tina female jimmy 2
tina female ken 6
NAME SEX NAME GRADE
------------------------ ------------ ------------------------ ----------
tina female richard 5
wendy female kerry 3
wendy female jimmy 2
wendy female ken 6
wendy female richard 5
已選擇16行。
注意:笛卡爾積用維恩圖是無法體現出來的。
自然連接:NATURAL JOIN
NATURAL JOIN: 在連接條件中使用等於(=)運算符比較被連接列的列值,但它使用選擇列表指出查詢結果集合中所包括的列,並刪除連接表中的重復列。如下所示
SQL> SELECT * FROM A NATURAL JOIN B;
NAME SEX GRADE
------------------------ ------------ ----------
kerry male 3
jimmy male 2
有種說法是,對兩張表中字段名和數據類型都相同的字段進行等值連接,並返回符合條件的結果 ,其實只要字段名相同,數據類型不同,也可以做NATURAL JOIN,如下所示:
SQL> create table test1(
2 id number(10),
3 name varchar2(12)
4 );
表已創建。
SQL> create table test2(
2 id varchar2(10),
3 nt varchar2(10));
表已創建。
SQL> insert into test1 values(
2 '1000','kk');
已創建 1 行。
SQL> insert into test2 values(
2 '1000','kkkk');
已創建 1 行。
SQL> select * from test1 natural join test2;
ID NAME NT
-------------------- ------------------------ --------------------
1000 kk kkkk
自然連接的兩個表的有多個字段都滿足有相同名稱,那么他們會被作為自然連接的條件,如下案例所示
SQL> drop table test1;
表已刪除。
SQL> drop table test2;
表已刪除。
SQL> create table test1(
2 id number(10),
3 name varchar2(10));
表已創建。
SQL> create table test2(
2 id number(10),
3 name varchar2(10));
表已創建。
SQL> insert into test1 select 1001, 'ken' from dual union all
2 select 1002,'kk' from dual;
已創建2行。
SQL> insert into test2 select 1001,'ken' from dual union all
2 select 1002,'kkk' from dual;
已創建2行。
SQL> select * from test1 natural join test2;
ID NAME
---------- --------------------
1001 ken
NATURAL JOIN的韋恩圖,其實和內連接是一樣的。如下所示:
SEMI JOIN
SEMI JOIN 多在子查詢exists中使用,對外部row source的每個鍵值,查找到內部row source匹配的第一個鍵值后就返回,如果找到就不用再查找內部row source其他的鍵值了。官方介紹案例如下
Using Semijoins: Example
SELECT * FROM departments
WHERE EXISTS
(SELECT * FROM employees
WHERE departments.department_id = employees.department_id
AND employees.salary > 2500)
ORDER BY department_name;
ANTI JOIN
ANTI JOIN多用於!=或not in 等查詢;如果找到滿足條件(!= not in)的不返回,不滿足條件(!= not in)的返回。和join相反。
Using Antijoins: Example
SELECT * ROM employees
WHERE department_id NOT IN
(SELECT department_id FROM departments
WHERE location_id = 1700)
ORDER BY last_name;
SELF JOIN
SELF JOIN其實就是某個表和其自身連接,連接方式可以是內連接,外連接,交叉連接
Using Self Joins: Example
SELECT e1.last_name||' works for '||e2.last_name
"Employees and Their Managers"
FROM employees e1, employees e2
WHERE e1.manager_id = e2.employee_id
AND e1.last_name LIKE 'R%';