了解聯結概念和語法

已完成

若要合併來自多個資料表的資料,最基本且最常見的方法就是使用 JOIN 作業。 有些人將 JOIN 視為 SELECT 陳述式中的個別子句,其他人則將其視為 FROM 子句的一部分。 本課程模組主要會將其視為 FROM 子句的一部分。 在本課程模組中,我們將會探索 T-SQL SELECT 陳述式中的 FROM 子句如何建立中繼虛擬資料表 (此資料表將會由後續的查詢階段所取用)。

FROM 子句和虛擬資料表

如果您了解在 SQL Server 處理查詢時執行作業的邏輯順序,便應該知道 SELECT 陳述式的 FROM 子句是系統所處理的第一個子句。 此子句會決定哪一個或哪些資料表是該查詢的資料列來源。 FROM 可以參考單一資料表或結合多個資料表,來作為您查詢的資料來源。 您可以將 FROM 子句視為會建立及填入虛擬資料表。 此虛擬資料表將會保存 FROM 子句的輸出,並由稍後套用的 SELECT 陳述式子句 (例如 WHERE 子句) 所使用。 隨著您為 FROM 子句加入額外功能 (例如聯結運算子),您應該將 FROM 子句元素的用途視為針對虛擬資料表新增或移除資料列。

由 FROM 子句所建立的虛擬資料表只是邏輯實體。 在 SQL Server 中,並不會建立任何實體資料表 (無論是持續性或暫時性) 來保存 FROM 子句的結果,因為該結果會傳遞到 WHERE 子句或查詢的其他部分。

由 FROM 子句所建立的虛擬資料表會包含所有已聯結資料表的資料。 您可以將結果想成「集合」,並將聯結結果想成文氏圖表。

A Venn diagram showing the set of an Employee table joined to a SalesOrder table

一直以來,T-SQL 語言都持續在擴展,以反映針對美國國家標準局 (ANSI) 的 SQL 語言標準所作出的變更。 其中一個最明顯的變更之處,在於 FROM 子句中聯結的語法。 在 ANSI SQL-89 標準中,是以逗號分隔清單於 FROM 子句中包含多個資料表來指定聯結。 為了判斷要包含哪些資料列而進行的任何篩選,都是在 WHERE 子句中執行,如下所示:

SELECT p.ProductID, m.Name AS Model, p.Name AS Product
FROM SalesLT.Product AS p, SalesLT.ProductModel AS m
WHERE p.ProductModelID = m.ProductModelID;

雖然 SQL Server 仍然支援此語法,但由於針對複雜聯結表示篩選的複雜度,因此並不建議使用此語法。 此外,如果意外省略 WHERE 子句,ANSI SQL-89 樣式的聯結很容易會變成笛卡兒乘積,並傳回過多的結果資料列,因而導致效能問題及潛在的錯誤結果。

學習使用 T-SQL 撰寫多資料表查詢時,請務必了解笛卡兒乘積的概念。 在數學中,笛卡兒乘積是兩個集合的乘積。 兩個元素之集合與六個元素之集合的乘積,是 12 個元素的集合,也就是 6 x 2。 其中一個集合中的每一個元素都會與另一個集合中的每一個元素合併。 在下列範例中,有一個具有兩個元素的名稱集合,以及一個具有三個元素的產品集合。 笛卡兒乘積會將每一個名稱與每一個產品合併,並產生六個元素。

Cartesian product

在資料庫中,笛卡兒乘積是將其中一個資料表中的每一個資料列,與另一個資料表中的每一個資料列相合併的結果。 一個具有 10 個資料列的資料表,與另一個具有 100 個資料列的資料表的乘積,是具有 1,000 個資料列的結果集。 JOIN 作業的底層結果是笛卡兒乘積,但對於大部分的 T-SQL 查詢來說,笛卡兒乘積並非理想的結果。 在 T-SQL 中,笛卡兒乘積會在聯結兩個輸入資料表,但不考慮兩者之間的任何關聯性時發生。 在沒有關聯性的任何資訊下,SQL Server 查詢處理器將會傳回所有可能的資料列組合。 雖然此結果可能會有一些實際的應用 (例如產生測試資料),其通常並不實用且可能會造成嚴重的效能影響。

隨著 ANSI SQL-92 標準的出現,也新增對 JOIN 和 ON 子句關鍵字的支援。 T-SQL 也支援此語法。 聯結在 FROM 子句中是使用適當的 JOIN 運算子來代表的。 資料表之間的邏輯關聯性 (其會成為篩選述詞) 是在 ON 子句上指定的。

下列範例會使用較新的語法來重述先前的查詢:

SELECT p.ProductID, m.Name AS Model, p.Name AS Product
FROM SalesLT.Product AS p
JOIN SalesLT.ProductModel AS m
    ON p.ProductModelID = m.ProductModelID;

注意

ANSI SQL-92 語法會降低意外產生笛卡兒乘積的機會。 在新增 JOIN 關鍵字之後,如果缺少 ON 子句,便會引發語法錯誤,除非已將 JOIN 指定為 CROSS JOIN。