如何在 MySQL 中为每个 ID 只选择一行?

Posted

技术标签:

【中文标题】如何在 MySQL 中为每个 ID 只选择一行?【英文标题】:How can I select only one row for each ID in MySQL? 【发布时间】:2009-06-23 18:53:28 【问题描述】:

我有一个 mysql 表,其中包含许多具有重复 ID 的条目(出于各种原因) 所以你可能有类似的东西

ID TIME DATA
1  xx   xx
2  xx   xx
3  xx   xx
1  xx   xx
3  xx   xx

我可以通过 php 运行什么查询来仅选择每个 ID 一次? 所以我希望我的结果集看起来像

ID TIME DATA
1  xx   xx
2  xx   xx
3  xx   xx

【问题讨论】:

结果中的 TIME 和 DATA 是什么?具有特定 id 的第一条记录的值(那么问题是为什么)?或者某些聚合函数(Count()、Sum() 甚至 Group_Concat())的结果?或者……什么? DISTINCT 不能解决您的问题。 【参考方案1】:

@karim79 和@Matthew Jones 给出的建议DISTINCT(ID) 可以解决此问题,这是对 DISTINCT 在 SQL 中的工作方式的常见误解。它没有帮助,因为DISTINCT 总是 适用于整行,而不是单个列。括号是不相关的,因为它们在查询 SELECT (1)SELECT 1 中。

@T Pops 给出的答案在这种情况下实际上很有帮助,因为 MySQL 以非标准方式处理 GROUP BY。请参阅我对“Selecting a Column not in GROUP BY”的回答以获得解释。

另一种解决方案是创造性地使用LEFT OUTER JOIN 来查询每个ID 的第一行。例如,假设TIME 列对于给定的ID 是唯一的,您可以执行以下操作:

SELECT t1.*
FROM MyTable t1 LEFT OUTER JOIN MyTable t2
  ON (t1.ID = t2.ID AND t1.TIME > t2.TIME)
WHERE t2.ID IS NULL;

如果t1 指向组中最早的行,则 t2 中不可能有更早日期的匹配行。因此,LEFT OUTER JOIN 将找不到匹配项,并将t2.* 保留为 NULL。

【讨论】:

很好的解释。我会在大约八小时后回来投票给你;-) @Sinan:这是评论说 JOIN 会表现不佳吗?您应该尝试使用 EXPLAIN 来查看这样的查询的优化计划。然后将其与 GROUP BY 或 DISTINCT 查询的计划进行比较,后者通常必须使用临时表。 @Bill 我今天的选票用完了,所以我无法支持你的答案。重要的是要指出 DISTINCT 在这里不是一个合适的“解决方案”。您的其余解释非常清楚。我的回答没有讽刺意味,只是真的很遗憾我当时不能投票给你。 谢谢!大声笑——我以为你在刻薄,好像你预计查询需要八小时才能完成,而你在投票之前一直在等待。 :-) 这个问题不值得+1,直到这个答案是官方解决方案。【参考方案2】:

看看 SELECT DISTINCT

【讨论】:

你们太棒了! DISTINCT 完美运行。 Group By 也很好,但我认为在这种情况下我需要区分。感谢所有回复的人! 嘿,我很想看看解决这个问题的实际 DISTINCT 查询!:) @Rudebuyrock ... 加入不同的 id 会不会更好? Aaah 所以你只是在寻找 id,而不是其他列。这解释了它:) 但是他的问题的结果中仍然有 TIME 和 DATA 列。【参考方案3】:

听起来您正在寻找GROUP BY

您可以使用类似以下的查询:

SELECT id, time, data GROUP BY ID

您肯定需要进行一些调整才能使该查询与您拥有的结构一起使用,但这是基本思想。

Tizag 对在 MySQL 和 PHP 中使用 GROUP BY 有很好的参考。

【讨论】:

+1 这实际上可以在 MySQL 中工作,因为 MySQL 以非标准方式处理 GROUP BY。 真的可以保证返回时间+同一行的数据吗? 不,它不保证从哪一行获取值。在实践中,它从首先物理存储的行中获取它们。如果这是 OP 想要的,那么他可以使用它(假设 MySQL 在未来版本中不会改变行为)。 见***.com/questions/1023347/… 但是一旦它选择了一行,它会从该行中取出所有列吗?第 1 行和第 4 行的数据不需要时间吗?【参考方案4】:

SQL 查询看起来像这样:

SELECT DISTINCT (ID), TIME, DATA FROM TableName

【讨论】:

这将选择两个记录 (1,'2009-05-16','x'),(1,'2009-04-11','y') 因为它们在 TIME 和数据。 我知道我忘记了什么。谢谢! 这就是我不在 MySQL 中编程的原因;它太宽容了。哦,好吧。 @Matthew Jones:这与 MySQL 无关。 DISTINCT 在标准 SQL 中的工作方式与在 MySQL 或任何其他品牌的数据库中的工作方式相同。 DISTINCT 总是 适用于整行,而不是单列,即使您使用括号。【参考方案5】:

向表中添加一个真正的主键,可能称为 RealId。

那么你可以:

select *
from YourTable
where realid in (
    select min(realid)
    from YourTable
    group by id
)

每个 id 会给你一行。

【讨论】:

【参考方案6】:
SELECT * FROM MyTable GROUP BY ID ORDER BY ID ASC

【讨论】:

以上是关于如何在 MySQL 中为每个 ID 只选择一行?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL:如何在 SQL 查询中为每个结果插入一条记录?

从 oracle 中为每个组选择最新行

如何在 MySQL 中为每个用户选择最多 3 个项目?

如何为 MySQL 中的每个组选择第一行?

如何排除具有相似列的行?

如何在 MySQL 中为每个类别创建一个 SQL 窗口函数列?