使用联接合并表

如何使用联接合并两个表格中的信息。

您有一个表格中的数据,想要与另一个表格中的数据合并。为此,您需要使用 JOIN 来告诉数据库一个表格中的行如何与另一个表格中的行相关联。(请注意,联接只适用于关系型数据库,并且您只能联接位于同一数据库中的表格。)

有关联接的背景信息,请查阅Metabase 中的联接,其中介绍了如何使用查询构建器创建联接——无需代码。请注意,“联接”这个术语有点误导,因为它并不是连接表格。它只是从两个(或更多)不同的表格中获取行,并返回一个结合了两个表格中列的行集。

本文将演示如何使用 SQL 和示例数据库创建联接,您可以在 Metabase 中通过点击 + 新建,选择 SQL 查询,然后选择 原始数据 > 示例数据库 来跟着操作。您还可以使用 AI 数据集生成器生成您自己的练习数据。

使用示例数据库的联接示例

假设我们想要提出一个问题,该问题返回包含多个表格中列的行。例如,我们想知道订单日期、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_idProducts 表中 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 是一个解析为真或假的表达式;数据库将只返回表达式为真的行。

联接多个表格

您可以通过列出每个联接类型及其条件来链式联接多个表格。这是一个包含 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 语句中包含多个真/假表达式来限制结果。这些真/假表达式被称为谓词。我们已经使用谓词联接了上面的表格,例如 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 联接类型的文章。

这有帮助吗?

感谢您的反馈!
分析师每周技巧
获取可行的见解
关于 AI 和数据的资讯,直接发送到您的收件箱
© . This site is unofficial and not affiliated with Metabase, Inc.