目錄
- 一、自聯結
- 二、自然聯結
- 三、外聯結
- 請參閱
目錄匯總:SQL 入門教程:面向萌新小白的零基礎入門教程
迄今為止,我們使用的只是行內結或等值聯結的簡單聯結,現在來看三種其他聯結:自聯結(self-join)、自然聯結(natural join)和外聯結 (outer join),
一、自聯結
如 使用表別名 所述,使用表別名的一個主要原因是能在一條 SELECT 陳述句中不止一次參考相同的表,下面舉一個例子,
假如要給與 Jim Jones 同一公司的所有顧客發送一封信件,這個查詢要求首先找出 Jim Jones 作業的公司,然后找出在該公司作業的顧客,下面是解決此問題的一種方法:
輸入▼
SELECT cust_id, cust_name, cust_contact
FROM Customers
WHERE cust_name = (SELECT cust_name
FROM Customers
WHERE cust_contact = 'Jim Jones');
輸出▼
cust_id cust_name cust_contact
-------- -------------- --------------
1000000003 Fun4All Jim Jones
1000000004 Fun4All Denise L. Stephens
分析▼
這是第一種解決方案,使用了子查詢,內部的 SELECT 陳述句 做了一個簡單檢索,回傳 Jim Jones 作業公司的 cust_name,該名字用于外部查詢的 WHERE 子句 中,以檢索出為該公司作業的所有雇員(子查詢 中講授了子查詢,更多資訊請參閱該部分),
現在來看使用聯結的相同查詢:
輸入▼
SELECT c1.cust_id, c1.cust_name, c1.cust_contact
FROM Customers AS c1, Customers AS c2
WHERE c1.cust_name = c2.cust_name
AND c2.cust_contact = 'Jim Jones';
輸出▼
cust_id cust_name cust_contact
------- ----------- --------------
1000000003 Fun4All Jim Jones
1000000004 Fun4All Denise L. Stephens
提示:Oracle 中沒有
ASOracle 用戶應該記住去掉
AS,
分析▼
此查詢中需要的兩個表實際上是相同的表,因此 Customers 表在 FROM 子句中出現了兩次,雖然這是完全合法的,但對 Customers 的參考具有歧義性,因為 DBMS 不知道你參考的是哪個 Customers 表,
解決此問題,需要使用表別名,Customers 第一次出現用了別名 c1,第二次出現用了別名 c2,現在可以將這些別名用作表名,例如,SELECT 陳述句使用 c1 前綴明確給出所需列的全名,如果不這樣,DBMS 將回傳錯誤,因為名為 cust_id、cust_name、cust_contact 的列各有兩個,DBMS 不知道想要的是哪一列(即使它們其實是同一列),WHERE 首先聯結兩個表,然后按第二個表中的 cust_contact 過濾資料,回傳所需的資料,
提示:用自聯結而不用子查詢
自聯結通常作為外部陳述句,用來替代從相同表中檢索資料的使用子查詢陳述句,雖然最終的結果是相同的,但許多 DBMS 處理聯結遠比處理子查詢快得多,應該試一下兩種方法,以確定哪一種的性能更好,
二、自然聯結
無論何時對表進行聯結,應該至少有一列不止出現在一個表中(被聯結的列),標準的聯結(聯結 中介紹的行內結)回傳所有資料,相同的列甚至多次出現,自然聯結排除多次出現,使每一列只回傳一次,
怎樣完成這項作業呢?答案是,系統不完成這項作業,由你自己完成它,自然聯結要求你只能選擇那些唯一的列,一般通過對一個表使用通配符(SELECT *),而對其他表的列使用明確的子集來完成,下面舉一個例子:
輸入▼
SELECT C.*, O.order_num, O.order_date,
OI.prod_id, OI.quantity, OI.item_price
FROM Customers AS C, Orders AS O,
OrderItems AS OI
WHERE C.cust_id = O.cust_id
AND OI.order_num = O.order_num
AND prod_id = 'RGAN01';
提示:Oracle 中沒有
ASOracle 用戶應該記住去掉
AS,
分析▼
在這個例子中,通配符只對第一個表使用,所有其他列明確列出,所以沒有重復的列被檢索出來,
事實上,我們迄今為止建立的每個行內結都是自然聯結,很可能永遠都不會用到不是自然聯結的行內結,
三、外聯結
許多聯結將一個表中的行與另一個表中的行相關聯,但有時候需要包含沒有關聯行的那些行,例如,可能需要使用聯結完成以下作業:
- 對每個顧客下的訂單進行計數,包括那些至今尚未下訂單的顧客;
- 列出所有產品以及訂購數量,包括沒有人訂購的產品;
- 計算平均銷售規模,包括那些至今尚未下訂單的顧客,
在上述例子中,聯結包含了那些在相關表中沒有關聯行的行,這種聯結稱為外聯結,
注意:語法差別
需要注意,用來創建外聯結的語法在不同的 SQL 實作中可能稍有不同,下面段落中描述的各種語法形式覆寫了大多數實作,在繼續學習之前請參閱你使用的 DBMS 檔案,以確定其語法,
下面的 SELECT 陳述句給出了一個簡單的行內結,它檢索所有顧客及其訂單:
輸入▼
SELECT Customers.cust_id, Orders.order_num
FROM Customers
INNER JOIN Orders ON Customers.cust_id = Orders.cust_id;
外聯結語法類似,要檢索包括沒有訂單顧客在內的所有顧客,可如下進行:
輸入▼
SELECT Customers.cust_id, Orders.order_num
FROM Customers
LEFT OUTER JOIN Orders ON Customers.cust_id = Orders.cust_id;
輸出▼
cust_id order_num
---------- ---------
1000000001 20005
1000000001 20009
1000000002 NULL
1000000003 20006
1000000004 20007
1000000005 20008
分析▼
類似 聯結 提到的行內結,這條 SELECT 陳述句使用了關鍵字 OUTER JOIN 來指定聯結型別(而不是在 WHERE 子句中指定),但是,與行內結關聯兩個表中的行不同的是,外聯結還包括沒有關聯行的行,在使用 OUTER JOIN 語法時,必須使用 RIGHT 或 LEFT 關鍵字指定包括其所有行的表(RIGHT 指出的是 OUTER JOIN 右邊的表,而 LEFT 指出的是 OUTER JOIN 左邊的表),上面的例子使用 LEFT OUTER JOIN 從 FROM 子句左邊的表(Customers 表)中選擇所有行,為了從右邊的表中選擇所有行,需要使用 RIGHT OUTER JOIN,如下例所示:
輸入▼
SELECT Customers.cust_id, Orders.order_num
FROM Customers
RIGHT OUTER JOIN Orders ON Customers.cust_id = Orders.cust_id;
注意:SQLite 外聯結
SQLite 支持
LEFT OUTER JOIN,但不支持RIGHT OUTER JOIN,幸好,如果你確實需要在 SQLite 中使用RIGHT OUTER JOIN,有一種更簡單的辦法,這將在下面的提示中介紹,
提示:外聯結的型別
要記住,總是有兩種基本的外聯結形式:左外聯結和右外聯結,它們之間的唯一差別是所關聯的表的順序,換句話說,調整
FROM或WHERE子句中表的順序,左外聯結可以轉換為右外聯結,因此,這兩種外聯結可以互換使用,哪個方便就用哪個,
還存在另一種外聯結,就是全外聯結(full outer join),它檢索兩個表中的所有行并關聯那些可以關聯的行,與左外聯結或右外聯結包含一個表的不關聯的行不同,全外聯結包含兩個表的不關聯的行,全外聯結的語法如下:
輸入▼
SELECT Customers.cust_id, Orders.order_num
FROM Customers
FULL OUTER JOIN Orders ON Customers.cust_id = Orders.cust_id;
注意:
FULL OUTER JOIN的支持MariaDB、MySQL 和 SQLite 不支持
FULL OUTER JOIN語法,
請參閱
- 使用表別名
- 使用不同型別的聯結
- 使用帶聚集函式的聯結
- 高級聯結(JOIN)練習題
(完)
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/296435.html
標籤:SQL Server
