How do you write a mysql query that returns the latest respective records?

detailCode :

Using the table (Messages) data structure:

+------+--------+--------+----------+------+--------+
|  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

The expected results should be (newest record from each sender):

+------+--------+--------+----------+------+--------+
|  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   |
+------+--------+--------+----------+------+--------+

However, after doing GROUP BY, the following results occur (incorrect sorting):

+------+--------+--------+----------+------+--------+
|  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   |
+------+--------+--------+----------+------+--------+

How do you get the latest records distinctively from each sender optimized without returning all records? I've tried JOINs and ORDER BY in the subquery, with the same results.

GMB :

If you want entire records, you need filtering, not aggregation.

If you are running MySQL 8.0, you can use row_number():

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

You can also filter with a correlated subquery (this will work on older versions of MySQL):

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

With an index on (fromid, sentdate), the correlated subquery might be an efficient solution.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=194887&siteId=1