【问题标题】:Select the 3 most recent records where the values of one column are distinct选择其中一列的值不同的 3 个最新记录
【发布时间】:2010-10-29 19:08:47
【问题描述】:

我有下表:

    id       time      text      otheridentifier
    -------------------------------------------
    1        6         apple     4
    2        7         orange    4
    3        8         banana    3
    4        9         pear      3
    5        10        grape     2

我想要做的是选择 3 个最近的记录(按时间降序),它们的 otheridentifiers 是不同的。所以在这种情况下,结果将是 id's: 5、4 和 2。

id = 3 将被跳过,因为有一个更新的记录具有相同的 otheridentifier 字段。

这是我尝试做的:

SELECT * FROM `table` GROUP BY (`otheridentifier`) ORDER BY `time` DESC LIMIT 3

但是,我最终得到了 id = 5、31 的行,而不是预期的 5、4、2。

有人能告诉我为什么这个查询不会返回我所期望的吗?我尝试将 ORDER BY 更改为 ASC,但这只是将返回的行重新排列为 1、3、5。

【问题讨论】:

    标签: mysql group-by sql-order-by


    【解决方案1】:

    这也是:

    SELECT * FROM
    OrigTable T INNER JOIN 
    ( 
    SELECT otheridentifier,max(time) AS duration
    FROM T
    GROUP BY otheridentifier) S
    ON S.duration = T.time AND S.otheridentifier = T.otheridentifier.
    

    【讨论】:

      【解决方案2】:

      您可以使用此查询获得正确答案:

      SELECT * FROM 
            (SELECT * FROM `table` order by time DESC)
                t group by otheridentifier
      

      【讨论】:

        【解决方案3】:

        我有类似的要求,但我有更高级的选择标准。使用其他一些答案我无法得到我所需要的,但我发现你仍然可以像这样做一个 GROUP BY 和 ORDER BY :

        SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t 
        GROUP BY t.otheridentifier
        

        【讨论】:

          【解决方案4】:

          Andomar's answer 可能是最好的,因为它不使用子查询。

          另一种方法:

          select *
          from   `table` t1
          where  t1.`time` in (
                              select   max(s2.`time`)
                              from     `table` t2
                              group by t2.otheridentifier
                              )
          

          【讨论】:

          • 我认为如果时间值不是唯一的,我会在这里看到一个问题——这可能会返回不应该的行。假设有一个时间值对于另一个标识符来说是最大值,但是对于另一个标识符来说是第二大的。这个查询不会返回两个其他标识符吗?不过我可能完全休息了,我还是有点累。 :)
          • @Rytmis:是的,我的查询和你的查询也是如此:) 呵呵
          • @Andomar:嗯,你确定我的查询吗?因为我只是通过添加一行 (6, 7, 'strawberry', 3) 来测试它——时间值 7 是具有 otheridentifier 4 的组中最大的,但在具有 otheridentifier 3 的组中是第二大的。我的查询仍然只返回 OP 想要的行。我的测试用例错了吗? :)
          • @Andomar:不,测试用例是正确的——这个查询返回“草莓”行,而我的没有。
          • @Rytmis:试试 (6,7,Strawberry,4)
          【解决方案5】:

          您可以自行加入表格以过滤每个 otheridentifier 的最后一个条目,然后取其中的前 3 行:

          SELECT last.*
          FROM `table` last
          LEFT JOIN `table` prev 
              ON prev.`otheridentifier` = last.`otheridentifier`
              AND prev.`time` < last.`time`
          WHERE prev.`id` is null
          ORDER BY last.`time` DESC 
          LIMIT 3
          

          【讨论】:

          • Andomar,你能解释一下 MySQL 在你的查询中是如何使用表 prev 的吗?我试图在本地查询中使用它,但收到一条错误消息,提示“database.prev”不存在。
          • 摆弄 OP 的数据和您的查询。不知道为什么这个答案被投票了 6 次 - 它在这里不起作用:sqlfiddle.com/#!2/ace0b/1
          • @acoder:你说得对,查询中有一个小错误:left join 后面的表名丢失了。我已经更新了答案。
          • 现在可以正常工作 - sqlfiddle.com/#!2/ace0b/6。感谢您的回复和更新。
          • 您似乎复制了 OP 不需要的结果。将小于切换为大于似乎可行,但这与大多数其他答案似乎使事情变得过于复杂。 ORDER BY MAX(time) 是 AFAICT 正确的解决方案。
          【解决方案6】:

          怎么样

          SELECT *, max(time) FROM `table`  group by otheridentifier
          

          【讨论】:

          • 编辑 - 这确实适用于 OP 的数据。我的查询中有一些额外的连接。这适用于 OP 的数据。 sqlfiddle.com/#!2/ace0b/2
          • 它似乎无法正常工作。在您的 sqlfiddle 中,它应该显示橙色和梨 - 它们的时间值更高。
          【解决方案7】:
          SELECT * FROM table t1 
          WHERE t1.time = 
              (SELECT MAX(time) FROM table t2 
               WHERE t2.otheridentifier = t1.otheridentifier)
          

          【讨论】:

          • 这将如何选择每个其他标识符的最新行?
          • @Andomar:当我没有完全清醒时,我不应该尝试回答问题。稍微更改了列名——看看现在是否更有意义。 :)
          【解决方案8】:

          它不会返回您期望的结果,因为分组发生在排序之前,正如 SQL 语句中子句的位置所反映的那样。不幸的是,你将不得不变得更漂亮才能获得你想要的行。试试这个:

          SELECT *
          FROM `table`
          WHERE `id` = (
              SELECT `id`
              FROM `table` as `alt`
              WHERE `alt`.`otheridentifier` = `table`.`otheridentifier`
              ORDER BY `time` DESC
              LIMIT 1
          )
          ORDER BY `time` DESC
          LIMIT 3
          

          【讨论】:

          • 我记得我花了几个小时来修复这样的 sql,结果 mysql 4.0 不支持嵌套查询;p
          • @Unreality:幸运的是,如果需要,大多数涉及子查询的解决方案都可以表示为连接。 :)
          • 尽可能避免子查询,因为它们很慢。改用 LEFT JOIN :)
          • @Jasie: dev.mysql.com/doc :) @marknt115: 是的,尽可能避免它们,但也只能这样。
          • @marknt15,没有子查询并不慢,因为它们是子查询。见percona.com/blog/2010/03/18/when-the-subselect-runs-faster
          猜你喜欢
          • 2019-07-13
          • 2019-05-02
          • 1970-01-01
          • 2016-01-20
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多