外聯接,自聯接與聯合。P417
關於聯接我們只認識了一半。我們還沒有見過
外聯接:在表中沒有匹配記錄的情況下返回記錄。
自聯接:可以聯接表本身。
聯合:可以合併查詢結果。
=========================================================
當你想清理舊數據的時候,可以考慮使用外聯接來找出不需要的值。
外聯接返回某張表的所有行,並且帶有來自另一張表的條件相符的行。
使用 內聯接 的時候,要對比來自兩張表的行,但是表的順序沒有影響。
先回顧一下:
SEKECT g.girl, t.toy
FROM girls g
INNER JOIN toys t
ON g.toy_id = t.toy_id;
這就是從兩張表中取出 toy_id 列同時出現在兩張表中的列。
======================================================
LEFT OUTER JOIN 接收左表的所有行,並用這些行與右表中的行匹配。當左表與右表有一對多的關係時,左外聯接特別有用。
在 LEFT OUTER JOIN 中,出現在 FROM 後,聯接前的表稱爲左表,聯接後的表是右表。
利用左外聯接找出每個女孩擁有的玩具。
女孩是左表,toys是右表
SELECT g.girl, t.toy
FROM girls g
LEFT OUTER JOIN toys t
ON g.toy_id = t.toy_id;
===============================================================
外聯接與多個相符結果:
雖然在另一個表中沒有相符的記錄,但是你還是會去的數據行,再匹配出多條記錄時就會取出多行。
右外聯接:
與左外聯接一樣,除了是用右表和左表對比:
SELECT g.girl, t.toy
FROM toys t
RIGHT OUTER JOIN girls g
ON g.toy_id = t.toy_id;
左右切換隻用改一個單詞。
==========================================================
利用外聯接:P429
找出小丑的頭領
現在數據庫模式如圖:
可以創建新表:列出每個小丑與他的頭領的ID。下是小丑組織圖並帶有每個小丑的ID。
以及一個小丑頭領表:
注意10號就是大BOSS,所以他的boss就是自己。
新表的位置:
再看一下現在的數據庫模式,並研究新表如何放入模式中:
左下角就是新表。
新表有一對一關係,就是主鍵id列,同時又一對多關係——boss_id列。這張表的主鍵與外鍵都來自 clown_info 表。
其實我們只要在 clown_info 表中加上新列來記錄每個小丑頭領的 ID,這一列就是 boss_id,與 clown_id 表中設計得一樣。
clown_boss 表中 boss_id 是外鍵,當我們把這一列加入 clown_info 時,仍然是外鍵,雖然它也在同一張表中。這叫做自引用外鍵。
自引用 表示的是它引用的是同一張表內的另一列的鍵。
連接表與它自己:
列出每個小丑的姓名和他們頭領的id:
SELECT name, boss_id FROM clown_info;
但是我們需要小丑的姓名和頭領的姓名。
SELECT c1.name, c2.name AS boss
FROM clown_info1 c1
INNER JOIN clown_info2 c2
ON c1.boss_id = c2.id;
這裏給 第二列取名爲 boss ,不會搞混。
==========================================================
剛剛出現了兩張相同的表供聯接,但是實際上正常規範數據庫相同表不會出現兩次。
於是我們改用自聯接模擬聯接兩張表的效果。
SELECT c1.name, c2.name AS boss
FROM clown_info c1
INNER JOIN clown_info c2
ONc1.boss_id = c2.id;
不用兩張表,而是用 clown_info 兩次。
第一次設定別名c1,第二次設定別名c2,然後內聯接 c1.boss_id 和c2.id
自聯接把單一表當初兩張完全相同的表進行查詢。
==========================================================
另一種去的多張表內容的方式:
以下爲 Greg 提到的三張表:
目前有三條獨立的 SELECT 語句:
SELECT title FROM job_cu rrent;
SELECT title FROM job_desired;
SELECT title FROM job_listings;
上述查詢沒問題,但是我們更想合併一下。
=============================================================
使用 UNION
UNION根據我們在 SELECT 中指定的列,把兩張或者更多張表的查詢結果合併到一個表中。可以把 UNION的查詢結果看做是 “重疊了” 每個 SELECT 的查詢結果。
SELECT title FROM job_current
UNION
SELECT title FROM job_desired
UNION
SELECT title FROM job_listings;
然後會發現結果集中沒有重複的記錄,但是職務沒有依序排列,於是我們加上 ORDER BY:P437
SELECT title FROM job_current ORDER BY title
UNION
SELECT title FROM job_desired ORDER BY title
UNION
SELECT title FROM job_listings ORDER BY title;
========================================================
UNION的使用限制
數據庫軟件可能會報錯,因爲同事用了多個 ORDER BY
UNION只能接受一個 ORDER BY,而且必須在語句末端。
爲此我們要做一些修改:
SELECT title FROM job_current
UNION
SELECT title FROM job_desired
UNION
SELECT title FROM job_listings
ORDER BY title;
==========================================
UNION ALL
方式和 UNION一樣,但是會返回列的所有內容:
SELECT title FROM job_current
UNION ALL
SELECT title FROM job_desired
UNION ALL
SELECT title FROM job_listings
ORDER BY title;
目前爲止,都是相同數據類型列的UNION,我們可能也要結合不同類的的UNION
數據會試着轉換爲向榮類型,如果無法轉換,查詢就失敗。
=========================================================
從聯合創建表
由 UNION 返回的數據類型不太容易分辨,除非用某種方式捕獲類型。使用 CREATE TABLE AS 可以捕獲 UNION的結果。
CREATE TABLE AS 接收來自 SELECT 查詢的結果,並把結果製作成一張表:
CREATE TABLE my_union AS
SELECT title FROM job_current UNION
SELECT title FROM job_desired
UNION SELECT title FROM job_listings;
===========================================================
INTERSECT 與 EXCEPT
交集與差集
方法和 UNION 基本一樣,找出查詢結果重疊的部分。
INTERSECT 只會返回同時在第一個與第二個查詢中的列。
SELECT title FROM job_current
INTERSECT
SELECT title FROM job_desired;
EXCEPT 返回只出現在第一個查詢,而不出現在第二個查詢中的列。
SELECT title FROM job_current
EXCEPT
SELECT title FROM job_desired;
=============================================================================
現在輪到子查詢和聯接的比較了。
之前說過,幾乎所有子查詢能幹的事情,聯接都能做。
P444
比如這裏有個子查詢語句:
SELECT mc.first_name, mc.last_name, mc.phone, jc.title
FROM job_current AS jc NATURE JOIN my_contacts AS mc
WHERE jc.title IN (SELECT title FROM job_listings);
現在我們用內聯接重寫:
SELECT mc.first_name, mc.last_name, mc.phone, jc.title
FROM job_current AS jc NATURE JOIN my_contacts AS mc
INNER JOIN job_listings jl
ON jc.title = jl.title;
問題是我們到底用哪個呢?
===============================================
我們看過子查詢如何變成聯接,現在看看變成子查詢的聯接:
SELECT c1.name, c2.name AS boss
FROM clown_info c1
INNER JOIN clown_info c2
ON c1.boss_id = c2.id;
改寫關聯子查詢:P449
SELECT c1.name,
(SELECT name FROM clown_info
WHERE c1.boss_id = id) AS boss
FROM clown_info c1;