天天看點

圖解 SQL join 語句内聯合(inner join)全外聯合(full outer join)左外聯合(left outer join)笛卡爾積 (交叉聯合(cross join))

假設我們有下面兩張表。表A在左邊,表B在右邊。我們給它們各四條記錄。

id name       id  name
-- ----       --  ----
1  Pirate     1   Rutabaga
2  Monkey     2   Pirate
3  Ninja      3   Darth Vader
4  Spaghetti  4   Ninja
           

我們用過name字段用幾種不同方式把這些表聯合起來,看能否得到和那些漂亮的韋恩圖在概念上的比對。

内聯合(inner join)

隻生成同時比對表A和表B的記錄集。(如下圖)

https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/iinner-join.png https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/iinner-join.png inner join https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/iinner-join.png
SELECT * FROM TableA
INNER JOIN TableB
ON TableA.name = TableB.name
 
id  name       id   name
--  ----       --   ----
1   Pirate     2    Pirate
3   Ninja      4    Ninja
           

全外聯合(full outer join)

生成表A和表B裡的記錄全集,包括兩邊都比對的記錄。如果有一邊沒有比對的,缺失的這一邊為null。(如下圖)

https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/Full-outer-join.png https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/Full-outer-join.png Full outer join https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/Full-outer-join.png
SELECT * FROM TableA
FULL OUTER JOIN TableB
ON TableA.name = TableB.name
 
id    name       id    name
--    ----       --    ----
1     Pirate     2     Pirate
2     Monkey     null  null
3     Ninja      4     Ninja
4     Spaghetti  null  null
null  null       1     Rutabaga       
null  null       3     Darth Vader

           

左外聯合(left outer join)

生成表A的所有記錄,包括在表B裡比對的記錄。如果沒有比對的,右邊将是null。(如下圖)

https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/Left-outer-join.png https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/Left-outer-join.png Left outer join https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/Left-outer-join.png
SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON TableA.name = TableB.name
 
id  name       id    name
--  ----       --    ----
1   Pirate     2     Pirate
2   Monkey     null  null
3   Ninja      4     Ninja
4   Spaghetti  null  null

           

為了生成隻在表A裡而不在表B裡的記錄集,我們用同樣的左外聯合,然後用where語句排除我們不想要的記錄。(如下圖)

https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/WHERE-TableB.id-IS-nul.png https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/WHERE-TableB.id-IS-nul.png WHERE TableB.id IS nul https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/WHERE-TableB.id-IS-nul.png
SELECT * FROM TableA
LEFT OUTER JOIN TableB
ON TableA.name = TableB.name
WHERE TableB.id IS null
 
id  name       id     name
--  ----       --     ----
2   Monkey     null   null
4   Spaghetti  null   null
           

為了生成對于表A和表B唯一的記錄集,我們用同樣的全外聯合,然後用where語句排除兩邊都不想要的記錄。(如下圖)

https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/WHERE-TableA.id-IS-null.png https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/WHERE-TableA.id-IS-null.png WHERE TableA.id IS null https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/WHERE-TableA.id-IS-null.png
SELECT * FROM TableA
FULL OUTER JOIN TableB
ON TableA.name = TableB.name
WHERE TableA.id IS null 
OR TableB.id IS null
 
id    name       id    name
--    ----       --    ----
2     Monkey     null  null
4     Spaghetti  null  null
null  null       1     Rutabaga
null  null       3     Darth Vader
           

笛卡爾積 (交叉聯合(cross join))

還有一種笛卡爾積或者交叉聯合(cross join),據我所知不能用韋恩圖表示:

SELECT * FROM TableA
CROSS JOIN TableB
           

這個把“所有”聯接到“所有”,産生4乘4=16行,遠多于原始的集合。如果你學過數學,你便知道為什麼這個聯合遇上大型的表很危險。

【2013-06-17 更新】下圖由 Moffatt 在 2008 年制作(點選可檢視大圖)。PS:Jeff Atwood 的文章寫于 2007 年。

https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/SQL-Joins.jpg https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/SQL-Joins.jpg SQL Joins https://link.jianshu.com?t=http://jbcdn2.b0.upaiyun.com/2013/05/SQL-Joins.jpg https://blog.codinghorror.com/a-visual-explanation-of-sql-joins/