【问题标题】:How to get the latest record in each group using GROUP BY? [duplicate]如何使用 GROUP BY 获取每个组的最新记录? [复制]
【发布时间】:2012-06-15 12:06:10
【问题描述】:

假设我有一个名为 messages 的表格,其中包含以下列:

id | from_id | to_id | subject | message | timestamp

我只想获取每个用户的最新消息,就像您在深入了解实际线程之前在 Facebook 收件箱中看到的那样。

这个查询似乎让我接近了我需要的结果:

SELECT * FROM messages GROUP BY from_id

但是,查询给我的是来自每个用户的最旧消息,而不是最新消息。

我想不出来这个。

【问题讨论】:

  • 这个问题还有更好的解决方案here

标签: mysql sql greatest-n-per-group


【解决方案1】:

您应该找出每个组(子查询)中的最后一个timestamp 值,然后将此子查询加入到表中 -

SELECT t1.* FROM messages t1
  JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp;

【讨论】:

  • +1 一个常见的问题,但非常感谢您不使用 MySQL 的功能,即允许选择中不属于 group by 的列!
  • 非常感谢!我能够毫无问题地加入其他表格。这么好的方法。
  • 这简直太完美了。
  • 对于那些不习惯 SQL 的人(比如我)。如果我没记错的话,'t1','t2'和'timestamp'是ALIASES,所以t2是内部SELECT的结果,而t2.timestamp的目标是MAX(timestamp)列,所以你可以从外部使用它在 ON 语句中选择。也许添加一些“AS”可能对像我这样的新手有很好的帮助:)
  • 我不喜欢它,我真的想对自己做一个内部连接而不是隐式子查询;但子查询似乎是唯一的方法。
【解决方案2】:

试试这个

SELECT * FROM messages where id in (SELECT max(id) FROM messages GROUP BY from_id ) order by id desc

【讨论】:

  • 虽然这段代码可以回答这个问题,但最好包含一些上下文,解释如何它是如何工作的以及何时 i> 使用它。从长远来看,纯代码的答案没有用处。
  • "SELECT max(id) FROM messages GROUP BY from_id" 这个内部查询,它首先按用户(from_id)对记录/消息进行分组,然后提取最大记录 ID。然后我们再次查询消息表以仅从内部查询结果集中获取最新记录/消息。
  • 最简单的解决方案恕我直言
  • 如果您想根据其他一些非主键列获取具有最大值的记录,这可能不起作用。
  • 这是我唯一的解决方法
【解决方案3】:

此查询返回每个 Form_id 的最后一条记录:

    SELECT m1.*
     FROM messages m1 LEFT JOIN messages m2
     ON (m1.Form_id = m2.Form_id AND m1.id < m2.id)
     WHERE m2.id IS NULL;

【讨论】:

  • 老实说,这个答案被低估了。这是唯一对我有效的解决方案,因为除了自动增量字段之外,我还按不同的字段进行分组,并且我必须选择最新的日期。
  • 这个答案帮助我让它与 Hibernate HQL 一起工作。其他答案都不起作用,因为 Hibernate 仅在 WHERE 和 SELECT 之后支持子查询。由于这个答案根本不使用任何子查询,所以效果很好。
【解决方案4】:

只是补充Devart所说的,下面的代码不是根据问题排序的:

SELECT t1.* FROM messages t1
  JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages GROUP BY from_id) t2
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp;

“GROUP BY”子句必须在主查询中,因为我们需要首先重新排序“SOURCE”以获得所需的“分组”,所以:

SELECT t1.* FROM messages t1
  JOIN (SELECT from_id, MAX(timestamp) timestamp FROM messages ORDER BY timestamp DESC) t2
    ON t1.from_id = t2.from_id AND t1.timestamp = t2.timestamp GROUP BY t2.timestamp;

问候,

【讨论】:

    【解决方案5】:

    这是一个标准问题。

    请注意,MySQL 允许您从 GROUP BY 子句中省略列,而标准 SQL 不允许,但是当您使用 MySQL 工具时通常不会获得确定性结果。

    SELECT *
      FROM Messages AS M
      JOIN (SELECT To_ID, From_ID, MAX(TimeStamp) AS Most_Recent
              FROM Messages
             WHERE To_ID = 12345678
             GROUP BY From_ID
           ) AS R
        ON R.To_ID = M.To_ID AND R.From_ID = M.From_ID AND R.Most_Recent = M.TimeStamp
     WHERE M.To_ID = 12345678
    

    我在To_ID 上添加了一个过滤器,以匹配您可能拥有的内容。没有它,查询也可以工作,但通常会返回更多数据。嵌套查询和外部查询中都不需要声明条件(优化器应该自动将条件下推),但重复显示的条件不会有任何害处。

    【讨论】:

    • 最新的标准 SQL 允许您省略 GROUP BY 中的列,并将它们包含在 SELECTHAVING 子句中,前提是它们在功能上依赖于 GROUP BY 组合 - 因此只会返回确定性结果。 (当然,MySQL 没有这样的检查。)
    • @ypercube 不确定这是否是这个地方,但你有什么好的链接吗?我无法理解如何通过依赖于 group by 中的项目来选择不在 group by 中的列如何成为确定性的,我能看到使其不确定的唯一方法是通过使用 order by。但是,查看示例可能有助于澄清问题。谢谢
    • GROUP BY pk 就是一个简单的例子。我的回答 here 链接到标准(副本)。
    • @ypercube 完美。谢谢。
    【解决方案6】:

    您需要订购它们。

    SELECT * FROM messages GROUP BY from_id ORDER BY timestamp DESC LIMIT 1

    【讨论】:

    • @BumbleB2na LIMIT 1 你的意思是?
    • 现在您将收到所有消息的最后一条消息,您需要一个 where 条件
    • oops mysql 不是 sql...你是对的
    • @BumbleB2na:实际上它也是 SQL,只是它是 MySQL SQL,而不是 SQL Server SQL(又名 Transact-SQL)。 :)
    • 它会给你同样的结果,只是得到的结果将按时间戳排序。
    猜你喜欢
    • 2016-05-15
    • 2013-06-27
    • 2020-12-19
    • 2021-01-20
    • 1970-01-01
    • 2016-03-11
    • 2020-08-11
    相关资源
    最近更新 更多