Получение последней записи в каждой группе - MySQL - PullRequest
824 голосов
/ 21 августа 2009

Существует таблица messages, которая содержит данные, как показано ниже:

Id   Name   Other_Columns
-------------------------
1    A       A_data_1
2    A       A_data_2
3    A       A_data_3
4    B       B_data_1
5    B       B_data_2
6    C       C_data_1

Если я выполню запрос select * from messages group by name, я получу результат как:

1    A       A_data_1
4    B       B_data_1
6    C       C_data_1

Какой запрос вернет следующий результат?

3    A       A_data_3
5    B       B_data_2
6    C       C_data_1

То есть последняя запись в каждой группе должна быть возвращена.

В настоящее время я использую этот запрос:

SELECT
  *
FROM (SELECT
  *
FROM messages
ORDER BY id DESC) AS x
GROUP BY name

Но это выглядит крайне неэффективно. Есть ли другие способы достижения того же результата?

Ответы [ 25 ]

1 голос
/ 02 мая 2018

Если производительность действительно важна, вы можете ввести в таблицу новый столбец с именем IsLastInGroup типа BIT.

Установите значение true в столбцах, которые являются последними, и сохраняйте его для каждой строки вставки / обновления / удаления. Запись будет медленнее, но вы получите пользу от чтения. Это зависит от вашего варианта использования, и я рекомендую его, только если вы ориентированы на чтение.

Ваш запрос будет выглядеть так:

SELECT * FROM Messages WHERE IsLastInGroup = 1
1 голос
/ 30 ноября 2016

Как насчет этого:

SELECT DISTINCT ON (name) *
FROM messages
ORDER BY name, id DESC;

У меня была похожая проблема (на жестком postgresql) и в таблице записей 1M. Это решение занимает 1,7 с против 44 с, созданных LEFT JOIN. В моем случае мне пришлось отфильтровать соответствующий компонент вашего поля name по значениям NULL, что привело к еще лучшей производительности на 0,2 с

.
1 голос
/ 18 июня 2016
select * from messages group by name desc
0 голосов
/ 09 апреля 2019

Вы видели https://github.com/fhulufhelo/Get-Last-Record-in-Each-MySQL-Group? у меня это работает

$sql = "SELECT c.id, c.name,  c.email, r.id, r.companyid, r.name,  r.email FROM companytable c LEFT JOIN ( SELECT * FROM revisiontable  WHERE id  IN ( SELECT MAX(id)  FROM revisiontable  GROUP BY companyid ))  r ON a.cid=b.r.id";
0 голосов
/ 07 апреля 2019

Вы можете группировать, считая, а также получить последний элемент группы, например:

SELECT 
    user,
    COUNT(user) AS count,
    MAX(id) as last
FROM request 
GROUP BY user
...