一尘不染

SQL仅选择列上具有最大值的行

mysql

我有此表用于文档(此处为简化版):

+------+-------+--------------------------------------+
| id   | rev   | content                              |
+------+-------+--------------------------------------+
| 1    | 1     | ...                                  |
| 2    | 1     | ...                                  |
| 1    | 2     | ...                                  |
| 1    | 3     | ...                                  |
+------+-------+--------------------------------------+

如何为每个ID选择一行,而仅选择最大转速?
根据上述数据,结果应包含两行:[1, 3, ...][2, 1, ..]。我正在使用 MySQL

目前,我在while循环中使用检查来检测和覆盖结果集中的旧版本。但这是获得结果的唯一方法吗?没有 SQL 解决方案吗?

更新
作为答案提示,有 一个SQL的解决方案,并且这里sqlfiddle演示

更新2
我在添加上面的 sqlfiddle 之后注意到,问题被投票的速率已经超过答案的投票率。那不是意图!小提琴基于答案,尤其是已接受的答案。


阅读 627

收藏
2020-05-17

共1个答案

一尘不染

乍一看…

您只需要一个GROUP BY带有MAX聚合函数的子句:

SELECT id, MAX(rev)
FROM YourTable
GROUP BY id

从来没有那么简单,是吗?

我只是注意到您也需要该content专栏。

在SQL中,这是一个非常常见的问题:查找行的整个数据,并在每个组标识符的列中找到某个最大值。我在职业生涯中听到了很多。实际上,这是我在当前工作的技术面试中回答的问题之一。

实际上,是如此普遍,以至于StackOverflow社区创建了一个标签来处理这样的问题:great-n-per-
group

基本上,有两种方法可以解决该问题:

结合简单的group-identifier, max-value-in-group子查询

用这种方法,您首先group-identifier, max-value-in- group在子查询中找到了(已经在上面解决了)。然后,您将表连接到子查询,group-identifier并且在和上具有相等性max-value- in-group

SELECT a.id, a.rev, a.contents
FROM YourTable a
INNER JOIN (
    SELECT id, MAX(rev) rev
    FROM YourTable
    GROUP BY id
) b ON a.id = b.id AND a.rev = b.rev

自我左联接,调整联接条件和过滤器

在这种方法中,您无需将表本身连接起来。平等是必不可少的group-identifier。然后,有2个明智的举动:

  1. 第二个连接条件是左侧值小于右侧值
  2. 当您执行步骤1时,实际具有最大值的行将NULL在右侧(它是LEFT JOIN,还记得吗?)。然后,我们过滤联接的结果,仅显示右侧为的行NULL

因此,您最终得到:

SELECT a.*
FROM YourTable a
LEFT OUTER JOIN YourTable b
    ON a.id = b.id AND a.rev < b.rev
WHERE b.id IS NULL;

结论

两种方法都带来完全相同的结果。

如果您有两行使用max-value-in-groupfor group-identifier,则两种方法的结果都将出现在这两行中。

两种方法都与SQL ANSI兼容,因此,无论其“味道”如何,都将与您喜欢的RDBMS一起使用。

两种方法都对性能很友好,但是您的工作量可能会有所不同(RDBMS,数据库结构,索引等)。因此,当您选择一种方法而不是另一种方法时,请选择 基准
。并确保选择最有意义的一种。

2020-05-17