

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# JOIN 子句
<a name="join-clause"></a>

SQL JOIN 子句用於根據通用欄位，結合兩個或多個資料表中的資料。結果可能會或可能不會改變，具體取決於指定的聯結方法。未在另一個資料表中找到相符項目時，左和右外部聯結會保留來自其中一個聯結資料表的值。

JOIN 類型和聯結條件的組合會決定哪些資料列包含在最終結果集中。然後 SELECT 和 WHERE 子句會控制傳回哪些資料欄，以及如何篩選資料列。了解不同的 JOIN 類型以及如何有效地使用它們是 SQL 的關鍵技能，因為它可讓您以靈活且強大的方式結合來自多個資料表的資料。

## 語法
<a name="join-clause-syntax"></a>

```
SELECT column1, column2, ..., columnn
FROM table1
join_type table2
ON table1.column = table2.column;
```

## Parameters
<a name="join-clause-parameters"></a>

 *SELECT 欄 1、欄 2、...、columnN*   
您要包含在結果集中的資料欄。您可以從 JOIN 中涉及的其中一個或兩個資料表中選取資料欄。

 *FROM 資料表 1*   
JOIN 操作中的第一個 （左） 資料表。

 *【加入 \$1 內部加入 \$1 左側 【外部】 加入 \$1 右側 【外部】 加入 \$1 完整 【外部】 加入】 資料表 2： *  
要執行的 JOIN 類型。JOIN 或 INNER JOIN 只會傳回兩個資料表中具有相符值的資料列。  
LEFT 【OUTER】 JOIN 會傳回左側資料表中的所有資料列，以及右側資料表中的相符資料列。  
RIGHT 【OUTER】 JOIN 會傳回右側資料表中的所有資料列，以及左側資料表中的相符資料列。  
FULL 【OUTER】 JOIN 會傳回兩個資料表中的所有資料列，無論是否相符。  
CROSS JOIN 會從兩個資料表建立資料列的笛卡爾產品。

 *ON table1.column = table2.column*   
聯結條件，指定如何比對兩個資料表中的資料列。聯結條件可以根據一個或多個資料欄。

 *WHERE 條件： *  
選用子句，可用於根據指定的條件進一步篩選結果集。

## 範例
<a name="Join_examples"></a>

下列範例是兩個資料表之間的聯結和 USING 子句。在這種情況下，資料欄 listid 和 eventid 會被用來作為聯結資料欄。結果限制為 5 個資料列。

```
select listid, listing.sellerid, eventid, listing.dateid, numtickets
from listing join sales
using (listid, eventid)
order by 1
limit 5;

listid | sellerid | eventid | dateid | numtickets
-------+----------+---------+--------+-----------
1      | 36861    | 7872    | 1850   | 10
4      | 8117     | 4337    | 1970   | 8
5      | 1616     | 8647    | 1963   | 4
5      | 1616     | 8647    | 1963   | 4
6      | 47402    | 8240    | 2053   | 18
```

# 聯結類型
<a name="join-types"></a>

## INNER
<a name="inner-join"></a>

這是預設聯結類型。傳回兩個資料表參考中具有相符值的資料列。

INNER JOIN 是 SQL 中使用的最常見聯結類型。這是根據通用資料欄或一組資料欄合併多個資料表資料的強大方式。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
INNER JOIN table2
ON table1.column = table2.column;
```

下列查詢將傳回客戶和訂單資料表之間存在相符 customer\$1id 值的所有資料列。結果集將包含 customer\$1id、name、order\$1id 和 order\$1date 資料欄。

```
SELECT customers.customer_id, customers.name, orders.order_id, orders.order_date
FROM customers
INNER JOIN orders
ON customers.customer_id = orders.customer_id;
```

下列查詢是 LISTING 資料表和 SALES 資料表之間的內部聯結 (沒有 JOIN 關鍵字)，其中 LISTING 資料表中的 LISTID 是介於 1 和 5 之間。此查詢會比對 LISTING 資料表 (左側資料表) 和 SALES 資料表 (右側資料表) 中 LISTID 資料欄的值。結果顯示 LISTID 1、4 和 5 符合條件。

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing, sales
where listing.listid = sales.listid
and listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

下列範例是一個內部聯結搭配 ON 子句。在此情況下，不會傳回 NULL 資料列。

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from sales join listing
on sales.listid=listing.listid and sales.eventid=listing.eventid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

以下查詢為 FROM 子句中兩個子查詢的內部聯結。查詢會尋找不同類別活動 (演奏會和表演) 的已售出和未售出票券數目。FROM 子句子查詢是*資料表*子查詢，可傳回多個資料欄和資料列。

```
select catgroup1, sold, unsold
from
(select catgroup, sum(qtysold) as sold
from category c, event e, sales s
where c.catid = e.catid and e.eventid = s.eventid
group by catgroup) as a(catgroup1, sold)
join
(select catgroup, sum(numtickets)-sum(qtysold) as unsold
from category c, event e, sales s, listing l
where c.catid = e.catid and e.eventid = s.eventid
and s.listid = l.listid
group by catgroup) as b(catgroup2, unsold)

on a.catgroup1 = b.catgroup2
order by 1;

catgroup1 |  sold  | unsold
----------+--------+--------
Concerts  | 195444 |1067199
Shows     | 149905 | 817736
```

## 左側 【外部 】
<a name="left-outer-join"></a>

傳回左側資料表參考的所有值，以及右側資料表參考的相符值，如果沒有相符項目，則附加 NULL。它也稱為*左側外部聯結*。

它會傳回左側 （第一個） 資料表的所有資料列，以及右側 （第二個） 資料表的相符資料列。如果右側資料表中沒有相符項目，則結果集將包含右側資料表中資料欄的 NULL 值。您可以省略 OUTER 關鍵字，而且可以直接將聯結寫入 LEFT JOIN。與 LEFT OUTER JOIN 相反的是 RIGHT OUTER JOIN，它會傳回右側資料表的所有資料列，以及左側資料表的相符資料列。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
LEFT [OUTER] JOIN table2
ON table1.column = table2.column;
```

下列查詢會傳回客戶資料表中的所有資料列，以及訂單資料表中的相符資料列。如果客戶沒有訂單，結果集仍會包含該客戶的資訊，以及 order\$1id 和 order\$1date 資料欄的 NULL 值。

```
SELECT customers.customer_id, customers.name, orders.order_id, orders.order_date
FROM customers
LEFT OUTER JOIN orders
ON customers.customer_id = orders.customer_id;
```

下列查詢是左側外部聯結。未在另一個資料表中找到相符項目時，左和右外部聯結會保留來自其中一個聯結資料表的值。左側和右側資料表分別是語法中最先和其次列出的資料表。NULL 值會用來填入結果集中的「空處」。此查詢會比對 LISTING 資料表 (左側資料表) 和 SALES 資料表 (右側資料表) 中 LISTID 資料欄的值。結果顯示 LISTIDs2 和 3 不會產生任何銷售。

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing left outer join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     2 | NULL   | NULL
     3 | NULL   | NULL
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

## 右 【 外部 】
<a name="right-outer-join"></a>

傳回右側資料表參考的所有值，以及左側資料表參考的相符值，如果沒有相符項目，則附加 NULL。它也稱為*正確的外部聯結*。

它會傳回右側 （秒） 資料表中的所有資料列，以及左側 （第一個） 資料表的相符資料列。如果左側資料表中沒有相符項目，則結果集將包含左側資料表中資料欄的 NULL 值。您可以省略 OUTER 關鍵字，而且可以直接將聯結寫入 RIGHT JOIN。RIGHT OUTER JOIN 與 RIGHT OUTER JOIN 相反是 LEFT OUTER JOIN，它會傳回左側資料表的所有資料列，以及右側資料表的相符資料列。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
RIGHT [OUTER] JOIN table2
ON table1.column = table2.column;
```

下列查詢會傳回客戶資料表中的所有資料列，以及訂單資料表中的相符資料列。如果客戶沒有訂單，結果集仍會包含該客戶的資訊，以及 order\$1id 和 order\$1date 資料欄的 NULL 值。

```
SELECT orders.order_id, orders.order_date, customers.customer_id, customers.name
FROM orders
RIGHT OUTER JOIN customers
ON orders.customer_id = customers.customer_id;
```

下列查詢是右側外部聯結。此查詢會比對 LISTING 資料表 (左側資料表) 和 SALES 資料表 (右側資料表) 中 LISTID 資料欄的值。結果顯示 LISTID 1、4 和 5 符合條件。

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing right outer join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

## 完整 【外部】
<a name="full-join"></a>

傳回兩個關係的所有值，並在沒有相符項目的 端附加 NULL 值。它也稱為*完整的外部聯結*。

它會傳回左側和右側資料表中的所有資料列，無論是否相符。如果沒有相符項目，則結果集將包含資料表中沒有相符資料列之資料欄的 NULL 值。您可以省略 OUTER 關鍵字，而且可以直接將聯結寫入 FULL JOIN。FULL OUTER JOIN 比 LEFT OUTER JOIN 或 RIGHT OUTER JOIN 更不常見，但在您需要查看兩個資料表中所有資料的某些情況下，即使沒有相符項目，它也很有用。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
FULL [OUTER] JOIN table2
ON table1.column = table2.column;
```

下列查詢將傳回來自客戶和訂單資料表的所有資料列。如果客戶沒有訂單，結果集仍會包含該客戶的資訊，以及 order\$1id 和 order\$1date 資料欄的 NULL 值。如果訂單沒有相關聯的客戶，結果集將包含該訂單，其中包含 customer\$1id 和名稱欄的 NULL 值。

```
SELECT customers.customer_id, customers.name, orders.order_id, orders.order_date
FROM customers
FULL OUTER JOIN orders
ON customers.customer_id = orders.customer_id;
```

下列查詢是完全聯結。未在另一個資料表中找到相符項目時，完全聯結會保留來自聯結資料表的值。左側和右側資料表分別是語法中最先和其次列出的資料表。NULL 值會用來填入結果集中的「空處」。此查詢會比對 LISTING 資料表 (左側資料表) 和 SALES 資料表 (右側資料表) 中 LISTID 資料欄的值。結果顯示 LISTIDs2 和 3 不會產生任何銷售。

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing full join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     1 | 728.00 | 109.20
     2 | NULL   | NULL
     3 | NULL   | NULL
     4 |  76.00 |  11.40
     5 | 525.00 |  78.75
```

下列查詢是完全聯結。此查詢會比對 LISTING 資料表 (左側資料表) 和 SALES 資料表 (右側資料表) 中 LISTID 資料欄的值。只有不會產生任何銷售 (ListID 2 和 3) 的資料列才會顯示在結果中。

```
select listing.listid, sum(pricepaid) as price, sum(commission) as comm
from listing full join sales on sales.listid = listing.listid
where listing.listid between 1 and 5
and (listing.listid IS NULL or sales.listid IS NULL)
group by 1
order by 1;

listid | price  |  comm
-------+--------+--------
     2 | NULL   | NULL
     3 | NULL   | NULL
```

## 【 左側 】 SEMI
<a name="left-semi-join"></a>

從與右側相符的資料表參考左側傳回值。它也稱為*左半聯結*。

它只會傳回左側 （第一個） 資料表中具有右側 （第二個） 資料表中相符資料列的資料列。它不會傳回右側資料表中的任何資料欄 - 只會傳回左側資料表中的資料欄。當您想要在一個資料表中找到符合另一個資料表的資料列時，不需要從第二個資料表傳回任何資料，LEFT SEMI JOIN 會很有用。LEFT SEMI JOIN 是將子查詢與 IN 或 EXISTS 子句搭配使用時更有效率的替代方案。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
LEFT SEMI JOIN table2
ON table1.column = table2.column;
```

對於訂單資料表中至少有一個訂單的客戶，下列查詢只會傳回客戶資料表中的 customer\$1id 和名稱資料欄。結果集不會包含訂單資料表中的任何資料欄。

```
SELECT customers.customer_id, customers.name
FROM customers
LEFT SEMI JOIN orders
ON customers.customer_id = orders.customer_id;
```

## CROSS JOIN
<a name="cross-join"></a>

傳回兩個關係的笛卡爾產品。這表示結果集將包含來自兩個資料表的所有可能資料列組合，而不會套用任何條件或篩選條件。

當您需要從兩個資料表產生所有可能的組合資料時，例如建立報告以顯示客戶和產品資訊的所有可能組合時，CROSS JOIN 非常有用。CROSS JOIN 與其他聯結類型 (INNER JOIN、LEFT JOIN 等） 不同，因為它在 ON 子句中沒有聯結條件。CROSS JOIN 不需要加入條件。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
CROSS JOIN table2;
```

下列查詢會傳回結果集，其中包含來自客戶和產品資料表的所有可能 customer\$1id、Customer\$1name、product\$1id 和 product\$1name 組合。如果客戶資料表有 10 個資料列，而產品資料表有 20 個資料列，則 CROSS JOIN 的結果集將包含 10 x 20 = 200 個資料列。

```
SELECT customers.customer_id, customers.name, products.product_id, products.product_name
FROM customers
CROSS JOIN products;
```

下列查詢是 LISTING 資料表和 SALES 資料表的交叉聯結或笛卡爾聯結，並且使用述詞來限制結果。此查詢會在 SALES 資料表和 LISTING 資料表中比對 LISTID 資料欄值，以找出兩個資料表中的 LISTID 1、2、3、4 和 5。結果顯示 20 個符合條件的資料列。

```
select sales.listid as sales_listid, listing.listid as listing_listid
from sales cross join listing
where sales.listid between 1 and 5
and listing.listid between 1 and 5
order by 1,2;

sales_listid | listing_listid
-------------+---------------
1            | 1
1            | 2
1            | 3
1            | 4
1            | 5
4            | 1
4            | 2
4            | 3
4            | 4
4            | 5
5            | 1
5            | 1
5            | 2
5            | 2
5            | 3
5            | 3
5            | 4
5            | 4
5            | 5
5            | 5
```

## ANTI 加入
<a name="anti-join"></a>

傳回左側資料表參考中與右側資料表參考不相符的值。它也稱為*左反聯結*。

當您想要在一個資料表中尋找資料列，而另一個資料表中沒有相符項目時，ANTI JOIN 是一項有用的操作。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
LEFT ANTI JOIN table2
ON table1.column = table2.column;
```

下列查詢將傳回所有尚未下訂單的客戶。

```
SELECT customers.customer_id, customers.name
FROM customers
LEFT ANTI JOIN orders
ON customers.customer_id = orders.customer_id
WHERE orders.order_id IS NULL;
```

## NATURAL
<a name="natural-join"></a>

指定兩個關係中的資料列將隱含地與具有相符名稱的所有資料欄的相等性相符。

它會自動比對兩個資料表之間具有相同名稱和資料類型的資料欄。它不需要您在 ON 子句中明確指定聯結條件。它將兩個資料表之間的所有相符資料欄合併為結果集。

當您要聯結的資料表具有具有相同名稱和資料類型的資料欄時，NATURAL JOIN 非常方便。不過，通常建議使用更明確的 INNER JOIN ... ON 語法可讓聯結條件更明確且更容易理解。

**語法:**

```
SELECT column1, column2, ..., columnn
FROM table1
NATURAL JOIN table2;
```

下列範例是兩個資料表 `employees`和 之間的自然聯結`departments`，具有下列資料欄：
+ `employees` 資料表：`employee_id`、`first_name`、`last_name`、 `department_id `
+ `departments` 資料表：`department_id`、 `department_name `

下列查詢會根據資料`department_id`欄傳回結果集，其中包含兩個資料表之間所有相符資料列的名字、姓氏和部門名稱。

```
SELECT e.first_name, e.last_name, d.department_name
FROM employees e
NATURAL JOIN departments d;
```

下列範例是兩個資料表之間的自然聯結。在這種情況下，兩個資料表中的 listid、sellerid、eventid 和 dateid 資料欄會具有相同的名稱和資料類型，因此會被用來作為聯結資料欄。結果限制為 5 個資料列。

```
select listid, sellerid, eventid, dateid, numtickets
from listing natural join sales
order by 1
limit 5;

listid | sellerid  | eventid | dateid | numtickets
-------+-----------+---------+--------+-----------
113    | 29704     | 4699    | 2075   | 22
115    | 39115     | 3513    | 2062   | 14
116    | 43314     | 8675    | 1910   | 28
118    | 6079      | 1611    | 1862   | 9
163    | 24880     | 8253    | 1888   | 14
```