Head First SQL 第十章

外聯接,自聯接與聯合。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;












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