SQL 入門教程:使用不同類型的聯結(JOIN)


目錄匯總: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 中沒有 AS

Oracle 用戶應該記住去掉 AS

分析▼

此查詢中需要的兩個表實際上是相同的表,因此 Customers 表在 FROM 子句中出現了兩次。雖然這是完全合法的,但對 Customers 的引用具有歧義性,因為 DBMS 不知道你引用的是哪個 Customers 表。

解決此問題,需要使用表別名。Customers 第一次出現用了別名 c1,第二次出現用了別名 c2。現在可以將這些別名用作表名。例如,SELECT 語句使用 c1 前綴明確給出所需列的全名。如果不這樣,DBMS 將返回錯誤,因為名為 cust_idcust_namecust_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 中沒有 AS

Oracle 用戶應該記住去掉 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 語法時,必須使用 RIGHTLEFT 關鍵字指定包括其所有行的表(RIGHT 指出的是 OUTER JOIN 右邊的表,而 LEFT 指出的是 OUTER JOIN 左邊的表)。上面的例子使用 LEFT OUTER JOINFROM 子句左邊的表(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,有一種更簡單的辦法,這將在下面的提示中介紹。

提示:外聯結的類型

要記住,總是有兩種基本的外聯結形式:左外聯結和右外聯結。它們之間的唯一差別是所關聯的表的順序。換句話說,調整 FROMWHERE 子句中表的順序,左外聯結可以轉換為右外聯結。因此,這兩種外聯結可以互換使用,哪個方便就用哪個。

還存在另一種外聯結,就是全外聯結(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 語法。

請參閱

(完)


免責聲明!

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



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