【问题标题】:Using GROUP BY or DISTINCT with a LEFT JOIN将 GROUP BY 或 DISTINCT 与 LEFT JOIN 一起使用
【发布时间】:2015-09-25 10:48:20
【问题描述】:

我有一张订单表和一张用户表。可以通过用户表中的条目下订单。

使用以下 MySQL 语句,如果有匹配的用户,我会得到重复的订单值:

SELECT o.id, u.id as 'user_id', u.name
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE o.status = 'active'

如果我添加GROUP BY o.id,它可以解决问题。

SELECT o.id, u.id as 'user_id'
FROM orders o
LEFT JOIN users u ON o.user_id = u.id
WHERE o.status = 'active'
GROUP BY o.id

如果我使用SELECT DISTINCT,它也可以工作。

我的问题是:

  1. 为什么会返回重复的字段?
  2. 使用 GROUP BY 或 SELECT DISTINCT 更正确吗?

【问题讨论】:

  • GROUP BY 是正确的
  • 使用 group by 获得准确的结果
  • 为什么select distinct 会出错或不准确?(回应 Rahautos 和 Ushma Shah)
  • SELECT DISTINCT 更快。但真正的问题出在其他地方:order 表中有重复的条目。 order.id 应该是表的PK,或者至少是UNIQUE INDEX。或者表orders 的行包含有关订单及其包含的项目的信息。如果是这种情况,您应该将其拆分为两个表:一个包含有关订单的信息(id、日期、用户等),另一个包含每个订单的产品(order.idFK)。
  • order.id 是主键。

标签: mysql group-by left-join


【解决方案1】:

您的 detail 查询——返回每一行的查询,而不是带有 DISTINCT 或 GROUP BY 的去重版本——在users 中找到多个与orders 中的每一行匹配的行。因此,它尽职尽责地返回所有这些行。

要正确解决您的问题,您需要弄清楚为什么每个订单有多个 users 行。也就是说,对于order.user_id 的某些值,users.id 的值有多个。

这对我来说似乎有点奇怪,但我不明白你的数据模型。您可能需要调查此数据异常。传统模式将使每个用户能够下多个订单,但每个订单仅与一个用户相关。在该架构中,此查询将为每个订单生成一行,但仍包括没有订单的用户:

SELECT u.id AS user_id, o.id AS order_id
  FROM users AS u
  LEFT JOIN orders AS o ON o.user_id = u.id

这就是你想要的吗?

与某些人的看法相反,GROUP BY orders.idSELECT DISTINCT orders.id, users.id不是相同的东西。事实上,您建议使用GROUP BY 会误用notorious MySQL extension to GROUP BY. 标准SQL 将拒绝您的GROUP BY。它只会接受GROUP BY orders.id, users.id,确实相当于DISTINCT。

【讨论】:

    【解决方案2】:

    为什么会返回重复的字段?

    它返回重复项,因为您没有应用任何东西来阻止它这样做。当您应用 GROUP BY 或 DISTINCT 时,您实际上会停止重复。

    使用 GROUP BY 还是 SELECT DISTINCT 更正确

    两者是等效的,可以根据您的方便使用。您可能会发现 DISTINCT 比 GROUP BY 更快,因为没有在您的表上创建索引。但这并不会使 GROUP BY 的使用不正确。如果创建了索引,那么它们都是等价的。

    【讨论】:

      【解决方案3】:

      您的查询根本不需要JOIN。您可以使用:

      SELECT o.id, o.user_id
      FROM orders o
      WHERE o.status = 'active';
      

      至于SELECT DISTINCTGROUP BY。两者在性能上应该相当(或非常接近)。他们所做的工作基本相同。

      GROUP BY 的优点是可以添加聚合函数。 DISTINCT 的优点是您不必列出所有列两次,它接受 *

      【讨论】:

      • 感谢您根据我的问题中的陈述是正确的。我精简了查询以使其更具可读性,但它确实从用户表中请求附加值。
      猜你喜欢
      • 1970-01-01
      • 2021-11-06
      • 2015-08-21
      • 1970-01-01
      • 2016-04-11
      • 2021-01-30
      • 1970-01-01
      • 1970-01-01
      • 2020-05-17
      相关资源
      最近更新 更多