Как вы пишете mysql запрос, который возвращает последние соответствующие записи? - PullRequest
0 голосов
/ 09 марта 2020

Использование структуры данных таблицы (Сообщения):

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

Как получить последние записи по-разному от каждого отправителя, оптимизированные без возврата всех записей? Я пробовал JOINs и ORDER BY в подзапросе с одинаковыми результатами.

Ответы [ 2 ]

1 голос
/ 09 марта 2020

Если вам нужны целые записи, вам нужна фильтрация , а не агрегация .

Если вы используете 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 голосов
/ 09 марта 2020

Проще подумать иначе: вам нужны записи с самым высоким индексом для каждого FromId

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

, а затем вы можете отсортировать их так, как вам захочется

...