您如何编写一个mysql查询以返回各自的最新记录?

问题描述 投票:0回答:3

使用表(消息)的数据结构:

+------+--------+--------+----------+------+--------+
|  id  | FromId |  ToId  | sentdate | text |  index |
+------+--------+--------+----------+------+--------+
| guid |    200 |    100 |  3/9/20  |  2c  |    6   |
| guid |    400 |    100 |  3/8/20  |  4a  |    5   |
| guid |    100 |    200 |  3/8/20  |  2b  |    4   |
| guid |    300 |    100 |  3/7/20  |  3a  |    3   |
| guid |    200 |    100 |  3/6/20  |  2a  |    2   |
| guid |    300 |    200 |  3/5/20  |  1a  |    1   |
+------+--------+--------+----------+------+--------+

SELECT * 
FROM `Messages` 
WHERE FromId IN (
    SELECT DISTINCT FromId 
    FROM `Messages` 
    WHERE ToId = '100')
GROUP BY FromId ORDER BY index DESC

预期结果应该是(每个发件人的最新记录:

+------+--------+--------+----------+------+--------+
|  id  | fromid |  toid  | sentdate | text |  index |
+------+--------+--------+----------+------+--------+
| guid |    200 |    100 |  3/9/20  |  2c  |    6   |
| guid |    400 |    100 |  3/8/20  |  4a  |    5   |
| guid |    300 |    100 |  3/7/20  |  3a  |    3   |
+------+--------+--------+----------+------+--------+

但是,在执行GROUP BY之后,会出现以下结果(排序不正确):

+------+--------+--------+----------+------+--------+
|  id  | fromid |  toid  | sentdate | text |  index |
+------+--------+--------+----------+------+--------+
| guid |    400 |    100 |  3/8/20  |  4a  |    5   |
| guid |    300 |    100 |  3/7/20  |  3a  |    3   |
| guid |    200 |    100 |  3/6/20  |  2a  |    2   |
+------+--------+--------+----------+------+--------+

您如何优化每个发件人的最新记录,而又不返回所有记录?我在子查询中尝试了JOIN和ORDER BY,结果相同。

mysql sql greatest-n-per-group
3个回答
0
投票

如果要整个记录,则需要过滤,而不是聚合

如果您正在运行MySQL 8.0,则可以使用row_number()

select *
from (
    select m.*, row_number() over(partition by fromid order by sentdate desc) rn
    from messages m
) t
where rn = 1

您还可以使用相关子查询进行过滤(这将在旧版本的MySQL上运行:]

select m.*
from messages m
where m.sentdate = (
    select max(m1.sentdate) from messages m1 where m1.fromid = m.fromid
)

使用在(fromid, sentdate)上的索引,相关子查询可能是一个有效的解决方案。


0
投票

您将加入一个合计:

SELECT m1.*
FROM messages AS m1
JOIN (
    SELECT FromId, MAX(sentdate) AS max_sentdate
    FROM messages AS x
    WHERE x.ToId = m1.ToId
    GROUP BY FromId
) AS m2 ON m1.FromId = m2.FromId AND m1.sentdate = m2.sentdate
WHERE m1.ToId = 100

0
投票

更容易反过来考虑:您需要每个FromId具有最高ID的记录

SELECT * FROM 'Messages' WHERE id IN (
   SELECT MAX(id) 
   FROM 'Messages' 
   WHERE ToId = 100 
   GROUP BY FromId
)

然后您可以根据需要对其进行排序

© www.soinside.com 2019 - 2024. All rights reserved.