SQL的JOIN用法總結



為了便於理解,本文將關鍵字全大寫,非關鍵字全小寫。實際使用沒有這個要求。

SQL的JOIN會用,用得好,能使SQL准確取到想取的數據,同時SQL語句還結構清晰易維護。它的通常形式為:

SELECT <結果字段集>
  FROM <左表>
  JOIN <右表> ON <連接條件>
 WHERE <篩選條件>

其中的JOIN可以換成以下的這些

JOIN, INNER JOIN, LEFT JOIN, RIGHT JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL JOIN, FULL OUTER JOIN, CROSS JOIN
但上面有些是等價的,一些是另一些的簡寫,整理如下:

全寫 簡寫
INNER JOIN JOIN
LEFT OUTER JOIN LEFT JOIN
RIGHT OUTER JOIN RIGHT JOIN
FULL OUTER JOIN FULL JOIN
CROSS JOIN (無)

 除了CROSS JOIN無須有、也不能有ON之外,其它的JOIN都必須有ON。

關於這些JOIN的基本用法,網上已經不少文章介紹,可以先看看  這個這個 或者百度一下“SQL連接JOIN”。

下文假設你已經明白這些JOIN的基本用法。

哪個表算左,哪個表算右?

如果是兩表,則XX JOIN左邊的表算左,右邊的表算右,與ON后面的條件的寫法無關。比如ON后面是等於號,等於號兩邊互換,不影響左右表的認定,也不影響查詢結果。
如果是多表,則XX JOIN左邊的全部表算左,右邊緊跟的那一個表算右,與ON后面的條件寫法無關。

ON后面如果有多個條件,會如何影響查詢的結果?

如果有多個條件,只看整個表達式的結果是True還是False,與部分表達式是否成立無關。比如 ON a.f1 = b.f1 AND a.f2 = b.f2,假如a.f1不等於b.f1,則不管a.f2是否等於b.f2,整個ON表達式都對查詢的結果無影響。ON后面不管多復雜,只看表達式整體運算的結果。

容易犯的一個誤區(重點來啦!)

以LEFT JOIN舉例,一些人認為LEFT JOIN從左表出發得到的結果,(假設沒有WHERE語句),左表的一行在結果中有且只有一行。
基於ON的關聯條件,結果分成3種情況:

1. 左表的1行,對應右表0行,則結果是1行,其中右表字段都為NULL

2. 左表的1行,對應右表1行,則結果是1行。

3. 左表的1行,對應右表n行(n>1),則結果是n行,其中左表字段被復制到結果中的n行中。

結論:

  • 對於LEFT JOIN,左表的一行,在結果中也可能出現多行
  • RIGHT JOIN同理:對於RIGHT JOIN,右表的一行,在結果中也可能出現多行!
  • 其它的JOIN都會在對面(左的對面是右)的表有多條數據符合ON條件時在結果中出現多次。
  • 沒有ON的CROSS JOIN,天生就會出現多行,左右表在結果中都可能出現多行!

當需要用FULL JOIN,但當前的數據庫又不支持怎么辦?

比如MySQL就不支持FULL JOIN。
這個網上有通用的解法,即是把FULL JOIN轉化成(LEFT JOIN) UNION (RIGHT JOIN)的結構。
支持FULL JOIN的寫法:

SELECT *
  FROM table_a AS a
  FULL JOIN table_b AS b ON a.a_id = b.a_id

不支持FULL JOIN的寫法:

SELECT *
  FROM table_a AS a
  LEFT JOIN table_b AS b ON a.a_id = b.a_id
 UNION
SELECT *
  FROM table_a AS a
 RIGHT JOIN table_b AS b ON a.a_id = b.a_id

但是實際SQL往往不會這么簡單。當table_a或table_b是一個子查詢(可能SQL很長)時,被寫成兩處,就會帶來維護的不便和兩處修改可能不一致的風險。

SELECT *
  FROM (
    SELECT * FROM table_a   -- 想象這是這是一個語句很長、很復雜的子查詢
  ) AS a
  LEFT JOIN (
    SELECT * FROM table_b   -- 想象這是這是另一個語句很長、很復雜的子查詢
  ) AS b ON a.a_id = b.a_id
 UNION
SELECT *
  FROM (
    SELECT * FROM table_a   -- 想象這是這是一個語句很長、很復雜的子查詢
  ) AS a
  LEFT JOIN (
    SELECT * FROM table_b   -- 想象這是這是另一個語句很長、很復雜的子查詢
  ) AS b ON a.a_id = b.a_id

改成下面這樣的寫法就能避免這個問題:

WITH a AS (
  SELECT * FROM table_a -- 想象這是這是一個語句很長、很復雜的子查詢
), b AS (
  SELECT * FROM table_b -- 想象這是這是另一個語句很長、很復雜的子查詢
)
SELECT *
  FROM a
  LEFT JOIN b ON a.a_id = b.a_id
 UNION
SELECT *
  FROM a
 RIGHT JOIN b ON a.a_id = b.a_id

現在你是不是對JOIN的認知加深了一些?有不清楚歡迎留言。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM