Oracle 中的join大法

    <h1>
        <!-- 主標題 -->
        <a id="lnkBlogTitle" href="http://www.cnblogs.com/kerrycode/">瀟湘隱者</a>
        <!-- 子標題 -->
        <small>
            </small>
    </h1>
</div>

<script type="text/javascript">
    var m = window.__blog.headerRendered;
    if (m) { m(__$("header")); }
</script>

<div id="wrapper">
    <div id="content">
        <script type="text/javascript">
            var m = window.__blog.preRenderPosts;
            if (m) { m(); }
        </script>

ORACLE的SQL JOIN方式小結

2016-10-07 12:13 by 瀟湘隱者, 13033 閱讀, 2 評論, 收藏, 編輯

在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等是表連接的物理實現方式。

 

clip_image001

 

我們先準備一個兩個測試表M與N(僅僅是爲了演示需要),如下腳本所示

SQL> CREATE TABLE M
  2  (
  3       NAME       VARCHAR2(12)
  4      ,SEX        VARCHAR2(6)
  5  );
 
Table created.
 
SQL> CREATE TABLE N
  2  (
  3         NAME       VARCHAR2(12)
  4      ,GRADE      NUMBER(2)
  5  );
 
Table created.
 
SQL> INSERT INTO M
  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 rows created.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> INSERT INTO N
  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 rows created.
 
SQL> COMMIT;
 
Commit complete.

 

內連接:INNER JOIN

 

INNER JOIN 它表示返回兩個表或記錄集連接字段的匹配記錄。如下所示,INNER JOIN 可以有三種實現方式:

 

SQL> SELECT M.NAME, M.SEX, N.GRADE 
  2  FROM M INNER JOIN N ON M.NAME=N.NAME;
 
NAME         SEX         GRADE
------------ ------ ----------
kerry        male            3
jimmy        male            2
 
SQL> SELECT M.NAME, M.SEX, N.GRADE
  2  FROM M, N 
  3  WHERE M.NAME=N.NAME;
 
NAME         SEX         GRADE
------------ ------ ----------
kerry        male            3
jimmy        male            2

 

 

第三種方式,使用USING,如下所示,這種寫法一般較少人使用。

 

SQL> SELECT NAME, M.SEX,N.GRADE
  2  FROM M INNER JOIN N USING(NAME);
 
NAME         SEX         GRADE
------------ ------ ----------
kerry        male            3
jimmy        male            2
 
SQL> 

clip_image002

 

注意,INNER JOIN可以用使用簡寫JOIN方式,如下所示,但是建議使用INNER JOIN 而不是JOIN這樣的語法。

 

clip_image003

 

如果我們用韋恩圖來解釋INNER JOIN,則非常一目瞭然、形象生動。可以用下面圖來表示(此圖以及下面的韋恩圖均來自鏈接http://pafumi.net/SQL_Joins.html ,本來想自己畫,無奈有些圖使用word不好實現,R語言不會。故在此借其圖用用)

 

clip_image004

 

 

外連接:OUTER JOIN

 

1 全連接:full join

全連接 :包含左、右兩個表的全部行,不管另外一邊的表中是否存在與它們匹配的行。不符合條件的,以空值代替。如下所示:

 
SQL> SELECT M.NAME, N.NAME, M.SEX, N.GRADE
  2  FROM M FULL OUTER JOIN N ON M.NAME=N.NAME;
 
NAME         NAME         SEX         GRADE
------------ ------------ ------ ----------
kerry        kerry        male            3
jimmy        jimmy        male            2
             ken                          6
             richard                      5
tina                      female
wendy                     female
 
6 rows selected.

clip_image005

 

FULL OUTER JOIN的韋恩圖如下所示:

 

clip_image006

 

 

2 左外連接:LEFT JOIN

 

左外連接又叫左連接 :意思是包含左邊表所有記錄,右邊所有的匹配的記錄,如果沒有則用空補齊。換句話說就是,列出左邊表全部的,及右邊表符合條件的,不符合條件的以空值代替。

SQL> SELECT M.NAME, N.NAME, M.SEX, N.GRADE
  2  FROM M LEFT OUTER JOIN N ON M.NAME=N.NAME;
 
NAME         NAME         SEX         GRADE
------------ ------------ ------ ----------
kerry        kerry        male            3
jimmy        jimmy        male            2
tina                      female
wendy                     female
 
SQL> SELECT M.NAME, N.NAME, M.SEX, N.GRADE
  2  FROM M LEFT JOIN N ON M.NAME=N.NAME;
 
NAME         NAME         SEX         GRADE
------------ ------------ ------ ----------
kerry        kerry        male            3
jimmy        jimmy        male            2
tina                      female
wendy                     female

 

 

在ORACLE 9i以及之前,使用在(+)來表示左連接,哪個帶(+)哪個需要條件符合的,另一個全部的。即放左表示右連接,放右表示左連接。這種寫法,如果不熟悉,就會有點陌生。其實也不是什麼新鮮事物,只是你不太熟悉而已。

 
SQL> SELECT M.NAME, N.NAME, M.SEX, N.GRADE
  2  FROM M, N
  3  WHERE M.NAME=N.NAME(+);
 
NAME         NAME         SEX         GRADE
------------ ------------ ------ ----------
kerry        kerry        male            3
jimmy        jimmy        male            2
tina                      female
wendy                     female
SQL> 

clip_image007

 

LEFT OUTER JOIN的韋恩圖如下所示:

clip_image008

 

 

3 右外連接:RIGHT JOIN

 

右外連接又叫右連接: 意思是包括右邊表所有記錄,匹配左邊表的記錄,如果沒有則以空補齊,換句話說,與左連接一樣,列出右邊表全部的,及左邊表符合條件的,不符合條件的用空值替代。如下所示

SQL> SELECT M.NAME, N.NAME, M.SEX, N.GRADE
  2  FROM M RIGHT OUTER JOIN N ON M.NAME=N.NAME;
 
NAME         NAME         SEX         GRADE
------------ ------------ ------ ----------
kerry        kerry        male            3
jimmy        jimmy        male            2
             ken                          6
             richard                      5
 
SQL> SELECT M.NAME, N.NAME, M.SEX, N.GRADE
  2  FROM M RIGHT JOIN N ON M.NAME=N.NAME;
 
NAME         NAME         SEX         GRADE
------------ ------------ ------ ----------
kerry        kerry        male            3
jimmy        jimmy        male            2
             ken                          6
             richard                      5
 
SQL> SELECT M.NAME, N.NAME, M.SEX, N.GRADE
  2  FROM M, N
  3  WHERE M.NAME(+) = N.NAME;
 
NAME         NAME         SEX         GRADE
------------ ------------ ------ ----------
kerry        kerry        male            3
jimmy        jimmy        male            2
             ken                          6
             richard                      5

clip_image009

 

 

笛卡爾積:CROSS JOIN

 

CROSS JOIN就是笛卡爾乘積連接,不需要任何關聯條件,實現M*N的結果集,其實這種SQL JOIN方式基本上只在理論上有意義,實際當中,很少有用的CORSS JOIN方式。

注意: cross join跟inner join、outer join等有所不同,不需要關鍵詞on,因爲它不需要相關字段做關聯。

SQL> SELECT M.NAME, M.SEX, N.NAME,N.GRADE
  2  FROM M CROSS JOIN N;
 
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 rows selected.

clip_image010

注意:笛卡爾積用維恩圖是無法體現出來的。

 

自然連接:NATURAL JOIN

 

NATURAL JOIN: 在連接條件中使用等於(=)運算符比較被連接列的列值,但它使用選擇列表指出查詢結果集合中所包括的列,並刪除連接表中的重複列。如下所示

SQL> SELECT * FROM M NATURAL JOIN N;
 
NAME         SEX         GRADE
------------ ------ ----------
kerry        male            3
jimmy        male            2

官方解釋:

The NATURAL keyword indicates that a natural join is being performed. A natural join is based on all columns in the two tables that have the same name. It selects rows from the two tables that have equal values in the relevant columns. When specifying columns that are involved in the natural join, do not qualify the column name with a table name or table alias

 

有種說法是,對兩張表中字段名和數據類型都相同的字段進行等值連接,並返回符合條件的結果 ,其實只要字段名相同,數據類型不同,也可以做NATURAL JOIN,如下所示:

SQL> CREATE TABLE TEST1
  2  (         
  3     ID     NUMBER(10),
  4     NAME   VARCHAR2(12)
  5  );
 
Table created.
 
SQLCREATE TABLE TEST2
  2  (
  3    ID    VARCHAR2(10),
  4     NT    VARCHAR2(12)
  5  );
 
Table created.
 
SQL> INSERT INTO TEST1
  2  VALUES(1000, 'KERRY');
 
1 row created.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> INSERT INTO TEST2
  2  VALUES('1000', 'KKK');
 
1 row created.
 
SQL> SELECT * FROM TEST1 NATURAL JOIN TEST2;
 
ID         NAME         NT
---------- ------------ ------------
1000       KERRY        KKK
 
SQL> 

clip_image011

 

自然連接的兩個表的有多個字段都滿足有相同名稱,那麼他們會被作爲自然連接的條件,如下案例所示

SQL> DROP TABLE TEST1;
 
Table dropped.
 
SQL> DROP TABLE TEST2;
 
Table dropped.
 
SQL> CREATE TABLE TEST1
  2  (
  3     ID     NUMBER(10),
  4     NAME   VARCHAR2(12)
  5  )
  6  ;
 
Table created.
 
SQL> CREATE TABLE TEST2
  2  (
  3    ID    NUMBER(10),
  4    NAME  VARCHAR2(12)
  5  );
 
Table created.
 
SQL> INSERT INTO TEST1
  2  SELECT 1000, 'KERRY' FROM DUAL UNION ALL
  3  SELECT 1001, 'KEN'   FROM DUAL;
 
2 rows created.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> INSERT INTO TEST2
  2  SELECT 1000, 'KKK' FROM DUAL UNION ALL
  3  SELECT 1001, 'KEN' FROM DUAL;
 
2 rows created.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> SELECT * FROM TEST1 NATURAL JOIN TEST2;
 
        ID NAME
---------- ------------
      1001 KEN

clip_image012

 

NATURAL JOIN的韋恩圖,其實和內連接是一樣的。如下所示:

clip_image004[1]

 

SEMI JOIN

 

  SEMI JOIN 多在子查詢exists中使用,對外部row source的每個鍵值,查找到內部row source匹配的第一個鍵值後就返回,如果找到就不用再查找內部row source其他的鍵值了。官方介紹案例如下

 

Using Semijoins: Example

 

In the following example, only one row needs to be returned from the departments table, even though many rows in the employees table might match the subquery. If no index has been defined on thesalary column in employees, then a semijoin can be used to improve query performance.

 

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

 

The following example selects a list of employees who are not in a particular set of departments:

 

SELECT * FROM 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 

 

The following query uses a self join to return the name of each employee along with the name of the employee’s manager. A WHERE clause is added to shorten the output.

 

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%’;

 

 

 

 

Employees and Their Managers  

 

——————————-

 

Rajs works for Mourgos

Raphaely works for King

Rogers works for Kaufling

Russell works for King

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章