使用聯結組合表格

如何使用聯結組合兩個表格中的資訊。

您有一個表格中的資料,想要與另一個表格中的資料組合。為此,您需要使用 JOIN 來告訴資料庫一個表格中的列與另一個表格中的列之間有何關聯。(請注意,聯結僅適用於關聯式資料庫。)

如需聯結的背景知識,請查看Metabase 中的聯結,其中逐步說明如何使用查詢產生器建立聯結,無需任何程式碼。請注意,「聯結」一詞在某種程度上具有誤導性,因為您並不是在連接表格。您是從兩個(或多個)不同的表格中取得列,並傳回一組新的列,其中組合了兩個表格中的欄。

本文說明如何使用 SQL 建立聯結,您可以在 Metabase 中按照步驟操作,方法是按一下+ 新增,選擇SQL 查詢,然後選取原始資料 > 範例資料庫

使用範例資料庫的聯結範例

假設我們想要提出一個問題,傳回包含多個表格欄位的列。例如,我們想要知道訂單日期、ID 和總計,但也想包含一些關於訂購產品的資訊。以下是我們想要產生的表格

| Order date | Order ID | Product Title       | Product Category | Product Rating | Order total |
|------------|----------|---------------------|------------------|----------------|-------------|
| 12/25/2016 | 448      | Rustic Paper Wallet | Gizmo            | 4.6            | 30.86326113 |
| ...        | ...      | ...                 | ...              | ...            | ...         |

現在讓我們看一下範例資料庫中的表格。我們會發現可以從兩個表格取得必要的欄位,「orders」表格

| ID  | Person | Product ID | Subtotal    | Tax  | Total       | Discount | Created At | Quantity | Person       | Product ID             |
|-----|--------|------------|-------------|------|-------------|----------|------------|----------|--------------|------------------------|
| 1   | 1      | 14         | 37.64814539 | 2.07 | 39.71814539 |          | 2/11/2019  | 2        | Hudson Borer | Awesome Concrete Shoes |
| ... | ...    | ...        | ...         | ...  | ...         | ...      | ...        | ...      | ...          | ...                    |

和「Products」表格

| ID  | Ean           | Title               | Category | Vendor                       | Price       | Rating | Created At |
|-----|---------------|---------------------|----------|------------------------------|-------------|--------|------------|
| 1   | 1018947080336 | Rustic Paper Wallet | Gizmo    | Swaniawski, Casper and Hilll | 29.46326113 | 4.6    | 7/19/2017  |
| ... | ...           | ...                 | ...      | ...                          | ...         | ...    | ...        |

請注意,在 SQL 編輯器中,您可以按一下書籍圖示以開啟資料參考側邊欄,從而查看關於資料庫中表格和欄位的資訊。學習如何聯結表格的大部分工作是瞭解您正在使用的表格以及它們彼此之間的關係。

The Data Reference sidebar in the SQL editor shows info about tables and fields in your database.

我們需要從這兩個表格中抓取欄位才能產生我們的目標結果,我們將使用聯結來完成此操作。

查詢

這是預先提供的答案

SELECT
  o.created_at AS "order date",
  o.id AS "order id",
  p.title AS "product title",
  p.category AS "product category",
  p.rating AS "product rating",
  o.total AS "order total"
FROM
-- joining orders to products
  orders AS o
  JOIN products AS p ON o.product_id = p.id

請注意,註解(以 -- 開頭的行)並非必要。它只是在那裡指出程式碼的關鍵部分:聯結陳述式。

此查詢告訴資料庫,「Orders」表格中的列可以與「Products」表格中的列組合,方法是將「Orders」表格中的外鍵「對齊」到「Products」表格的實體鍵(也稱為主鍵)。我們也為每個表格設定了別名(orders AS oproducts AS p),因此您可以在 SELECT 陳述式中分辨每個欄位來自哪個表格(o.created_at 來自「orders」表格,依此類推)。

實體鍵是指表格中包含每個列唯一識別碼的欄位。在「Orders」表格中,每個列都是一個具有 ID 的訂單。在「Products」表格中的產品也是如此:每個列都是一個具有 ID 的產品。外鍵是指引用另一個表格中實體鍵的欄位。在此案例中,「Orders」表格包含一個 product_id,它引用「Products」表格中的特定列。如果我們在資料參考側邊欄中查看「Products」表格,我們會看到它有兩個連線,一個連線到「Orders」表格,另一個連線到「reviews」表格。

The Products table has connections to the Orders and Reviews tables.

我們可以透過將「Products」中的每一列與「Orders」中的每一列組合,然後使用像這樣的 WHERE 子句進行篩選,來獲得相同的結果

SELECT
  o.created_at as "order date",
  o.id as "order id",
  p.title as "product title",
  p.category as "product category",
  p.rating as "product rating",
  o.total as "order total"

-- a join using a WHERE clause to "line up" the entity and foreign keys
FROM
  orders AS o,
  products AS p
WHERE
  o.product_id = p.id

此查詢表示:將「Orders」表格中的每一列與「Products」表格中的每一列組合,然後篩選結果,僅包含「Orders」表格中的 product_id 與「Products」表格中的 id 相符的列。我們建議您使用第一種形式(使用 ON)以避免混淆:ON 始終引入聯結的條件,而 WHERE 用於各種篩選。如需更多資訊,請查看撰寫 SQL 查詢的最佳實務

讓我們深入探討聯結陳述式

FROM
-- joining orders to products
  orders AS o
  JOIN products AS p ON o.product_id = p.id

當您聯結表格時,您可以使用 ON 關鍵字來指定表格 A(Orders)中的哪個欄位對應於表格 B(Products),以便資料庫瞭解如何「對齊」資料。o.product_id = p.id 是一個解析為 true 或 false 的表達式;資料庫將只傳回表達式為 true 的列。

聯結多個表格

您可以透過列出每個聯結類型及其條件來串聯多個聯結。以下是一個包含「people」表格欄位的聯結

SELECT
  *
FROM
  orders AS o
  JOIN products AS p ON o.product_id = p.id
  JOIN people AS u ON o.user_id = u.id

您需要在這裡進行大量水平捲動,因為此查詢將產生許多欄位(實際上是每個表格的所有欄位)。您會看到逐列重複的資訊。例如,結果會針對客戶下的每個訂單重複客戶地址。

| ID  | USER_ID | PRODUCT_ID | SUBTOTAL    | TAX | TOTAL       | DISCOUNT | CREATED_AT       | QUANTITY | ID  | EAN           | TITLE               | CATEGORY | VENDOR                       | PRICE       | RATING | CREATED_AT      | ID  | ADDRESS                 | EMAIL                  | PASSWORD                             | NAME         | CITY    | LONGITUDE  | STATE | SOURCE | BIRTH_DATE | ZIP   | LATITUDE | CREATED_AT    |
|-----|---------|------------|-------------|-----|-------------|----------|------------------|----------|-----|---------------|---------------------|----------|------------------------------|-------------|--------|-----------------|-----|-------------------------|------------------------|--------------------------------------|--------------|---------|------------|-------|--------|------------|-------|----------|---------------|
| 448 | 61      | 1          | 29.46326113 | 1.4 | 30.86326113 |          | 12/25/2016 22:19 | 2        | 1   | 1018947080336 | Rustic Paper Wallet | Gizmo    | Swaniawski, Casper and Hilll | 29.46326113 | 4.6    | 7/19/2017 19:44 | 61  | 7100 Hudson Chapel Road | labadie.lina@gmail.com | 2da78e08-2bf7-41b8-a737-1acd815fb99c | Lina Labadie | Catawba | -81.017265 | NC    | Google | 3/28/1984  | 28609 | 35.69917 | 6/5/2016 4:03 |
| ... | ...     | ...        | ...         | ... | ...         | ...      | ...              | ...      | ... | ...           | ...                 | ...      | ...                          | ...         | ...    | ...             | ... | ...                     | ...                    | ...                                  | ...          | ...     | ...        | ...   | ...    | ...        | ...   | ...      | ...           |

在上面的查詢中,您可以透過將 SELECT 陳述式中的 * 替換為僅指定您需要的欄位,來減少傳回的欄位數。

多條件聯結

您可以在 ON 陳述式中包含多個 true/false 表達式以限制結果。這些 true/false 表達式稱為述詞。我們已經一直在使用述詞來聯結上面的表格,例如 o.user_id = u.id

假設我們想要知道

  • 訂單的平均價格,
  • 依產品類別,
  • 以全價售出的。

我們需要使用「Orders」表格中的資料計算單價,並從「Products」表格中抓取產品類別和定價。以下是我們的查詢

SELECT
  p.category AS "Product category",
  AVG(p.price) AS "Average price",
  COUNT(*) AS "Count of full price orders"
FROM
  orders AS o
  -- first predicate
  JOIN products AS p ON o.product_id = p.id
  -- second predicate: calculate the unit price
  -- and see if it corresponds to the product's listed price.
  AND o.subtotal / o.quantity = p.price
WHERE
  -- guard against divide-by-zero scenarios
  o.quantity > 0
GROUP BY
  p.category
ORDER BY
  COUNT(*) DESC

這給我們

|Product category|Average price|Count of full price orders|
|----------------|-------------|--------------------------|
|Widget          |54.96699655  |168                       |
|Gizmo           |51.49700878  |137                       |
|Gadget          |54.87034242  |136                       |
|Doohickey       |51.69197973  |123                       |

不同類型的聯結

我們在整篇文章中使用的特定聯結類型稱為內部聯結。還有其他聯結表格的方法;請參閱我們關於SQL 聯結類型的文章。

下一步:SQL 聯結類型

瞭解使用不同 SQL 聯結類型所需的一切知識。

下一篇文章