You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL按用户分组取MAX(created_at)无法返回对应正确元组的问题求助

嘿,我来帮你捋清楚这个问题的根源和解决办法!

问题原因

你遇到的这个问题,核心在于MySQL的非标准GROUP BY行为(当ONLY_FULL_GROUP_BY模式未开启时)。

看你写的子查询:

SELECT max(mb.created_at), message_id FROM `messages` mb WHERE mb.created_at <= '2021-07-24' group by user_id

这里message_id既没有出现在GROUP BY子句中,也没有被聚合函数(比如MAX、MIN)包裹。在默认的宽松模式下,MySQL不会报错,但它会随机从该用户的分组记录里挑选一个message_id返回,而不是和MAX(created_at)对应的那条记录的ID——这就是为什么user_id=1时,结果里的message_id是5,而不是你预期的6。

解决方案

这里有几种靠谱的方法,能精准获取每个用户最后创建的那条完整消息:

方法1:关联子查询(兼容性好,适合所有MySQL版本)

先通过子查询算出每个用户的最大created_at,再和原表关联匹配对应的完整记录:

SELECT ma.*
FROM messages ma
INNER JOIN (
    SELECT user_id, MAX(created_at) AS latest_created
    FROM messages
    WHERE created_at <= '2021-07-24'
    GROUP BY user_id
) mc ON ma.user_id = mc.user_id AND ma.created_at = mc.latest_created

这个方法逻辑直白,能确保拿到和最新创建时间对应的那条记录。

方法2:窗口函数(MySQL 8.0及以上版本推荐)

如果你的MySQL是8.0或更新的版本,用ROW_NUMBER()窗口函数会更简洁高效:

SELECT message_id, user_id, date_sent, created_at
FROM (
    SELECT 
        *,
        ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS row_rank
    FROM messages
    WHERE created_at <= '2021-07-24'
) ranked_messages
WHERE row_rank = 1

这里PARTITION BY user_id按用户分组,ORDER BY created_at DESC把每个用户最新的消息排在第一位,最后筛选row_rank=1的记录就是你要的结果。

方法3:单用户场景的简化写法

如果只是查询单个用户的最新消息,可以直接用ORDER BY + LIMIT:

SELECT *
FROM messages
WHERE user_id = 1 AND created_at <= '2021-07-24'
ORDER BY created_at DESC
LIMIT 1

额外提示

建议开启ONLY_FULL_GROUP_BY SQL模式,这样MySQL会对不符合标准SQL规范的GROUP BY语句直接报错,避免再出现这种“随机返回字段值”的意外情况。临时开启可以执行:

SET sql_mode = 'ONLY_FULL_GROUP_BY';

如果需要永久生效,要修改MySQL的配置文件(my.cnf或my.ini),在[mysqld]段添加sql_mode = ONLY_FULL_GROUP_BY后重启服务。

内容的提问来源于stack exchange,提问作者Rob

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 23:27:32