你如何编写一个 mysql 查询 returns 最新的相应记录?
How do you write a mysql query that returns the latest respective records?
使用 table(消息)数据结构:
+------+--------+--------+----------+------+--------+
| 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,结果相同。
如果你想要整个记录,你需要过滤,而不是聚合。
如果你是运行MySQL8.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)
上的索引,相关子查询可能是一个有效的解决方案。
反过来想更容易:您需要每个 FromId 具有最高索引的记录
SELECT * FROM 'Messages' WHERE id IN (
SELECT MAX(index)
FROM 'Messages'
WHERE ToId = 100
GROUP BY FromId
)
然后你可以随意排序
使用 table(消息)数据结构:
+------+--------+--------+----------+------+--------+
| 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,结果相同。
如果你想要整个记录,你需要过滤,而不是聚合。
如果你是运行MySQL8.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)
上的索引,相关子查询可能是一个有效的解决方案。
反过来想更容易:您需要每个 FromId 具有最高索引的记录
SELECT * FROM 'Messages' WHERE id IN (
SELECT MAX(index)
FROM 'Messages'
WHERE ToId = 100
GROUP BY FromId
)
然后你可以随意排序