如何解决MySQL Max of a Date 未返回正确的元组
我有一个“消息”表,用于存储一段时间内发送给人们的关于某些项目的消息。
messages表的结构是:
message_id 用户身份 发送日期 created_at
对于每个用户,我可以在表中有多个元组。 这些消息有些已经发送,有些还没有发送。
我正在尝试为每个用户获取最后创建的消息。 我正在使用 max(created_at) 和 group_by(user_id),但关联的 message_id 不是与 max(created_id) 元组关联的那个。
表格数据:
message_id | user_id | date_sent | created_at
----------------------------------------------
1 1 2021-07-01 2021-07-01
2 1 2021-07-02 2021-07-02
3 2 2021-07-01 2021-07-01
4 3 2021-07-04 2021-07-04
5 1 2021-07-22 2021-07-22
6 1 NULL 2021-07-23
7 2 NULL 2021-07-29
8 1 NULL 2021-07-29
9 3 2021-07-29 2021-07-29
我的选择:
select * from messages ma right join
( SELECT max(mb.created_at),message_id
FROM `messages` mb WHERE mb.created_at <= '2021-07-24'
group by user_id)
mc on ma.message_id=mc.message_id
结果是
message_id | user_id | date_sent | created_at
----------------------------------------------
5 1 2021-07-22 2021-07-23
3 2 2021-07-01 2021-07-01
4 3 2021-07-04 2021-07-04
我不知道为什么,但是对于用户 1,返回的 message_id 不是与具有 max(created_at) 的元组关联的那个。
我期望是:(获取按 user_id 分组的 select 的 max(date_sent) 元组)
message_id | user_id | date_sent | created_at
----------------------------------------------
6 1 NULL 2021-07-23
3 2 2021-07-01 2021-07-01
4 3 2021-07-04 2021-07-04
有什么想法吗?有什么帮助吗? 谢谢。
解决方法
您在 MySQL 的 notorious nonstandard extension to GROUP BY 上磕磕绊绊。它给你一种错觉,你可以做你不能做的事情。示例
SELECT max(created_at),message_id
FROM messages
GROUP BY user_id
其实就是
SELECT max(created_at),ANY_VALUE(message_id)
FROM messages
GROUP BY user_id
其中 ANY_VALUE() 表示 MySQL 可以从该用户的消息中选择它认为最方便的任何 message_id。那不是你想要的。
要解决您的问题,您首先需要使用子查询为每个 created_at
查找最新的 user_id
日期。 Fiddle。
SELECT user_id,MAX(created_at) created_at
FROM messages
WHERE created_at <= '2021-07-24'
GROUP BY user_id
然后,您需要找到在该日期创建的特定 user_id 的消息。为此使用子查询。 Fiddle
SELECT a.*
FROM messages a
JOIN (
SELECT user_id,MAX(created_at) created_at
FROM messages
WHERE created_at <= '2021-07-24'
GROUP BY user_id
) b ON a.user_id = b.user_id AND a.created_at = b.created_at
看看 JOIN 是如何工作的?它为每个用户提取与最新日期匹配的行。
有一个可能的优化。如果
- 您的 message_id 是一个自动递增的主键,并且
- 您从不更新 created_at 列,而仅在插入行时将它们设置为当前日期
那么每个user_id的最新消息也是message_id最大的消息。在这种情况下,您可以改用此查询。 Fiddle
SELECT a.*
FROM messages a
JOIN (
SELECT user_id,MAX(message_id) message_id
FROM messages
WHERE created_at <= '2021-07-24'
GROUP BY user_id
) b ON a.message_id=b.message_id
由于主键索引的工作方式,这可以更快。
这里你需要一个普通的 JOIN 而不是 RIGHT 或 LEFT JOIN:普通的 JOIN 只返回匹配 ON 条件的行。
专业提示几乎没有人真正使用 RIGHT JOIN。当您想要那种 JOIN 时,请使用 LEFT JOIN。您不希望这种连接来解决这个问题。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。