Сортировка MySQL по дате с GROUP BY
мой стол titles
выглядит так
id |group|date |title
---+-----+--------------------+--------
1 |1 |2012-07-26 18:59:30 | Title 1
2 |1 |2012-07-26 19:01:20 | Title 2
3 |2 |2012-07-26 19:18:15 | Title 3
4 |2 |2012-07-26 20:09:28 | Title 4
5 |2 |2012-07-26 23:59:52 | Title 5
мне нужен последний результат из каждой группы упорядочены по дате в порядке убывания. Что-то вроде этого!--6-->
id |group|date |title
---+-----+--------------------+--------
5 |2 |2012-07-26 23:59:52 | Title 5
2 |1 |2012-07-26 19:01:20 | Title 2
пробовал
SELECT *
FROM `titles`
GROUP BY `group`
ORDER BY MAX( `date` ) DESC
но я получаю первые результаты от групп. Такой
id |group|date |title
---+-----+--------------------+--------
3 |2 |2012-07-26 18:59:30 | Title 3
1 |1 |2012-07-26 19:18:15 | Title 1
что я делаю не так? Этот запрос будет сложнее, если я использую LEFT JOIN?
8 ответов
на этой странице было очень полезно для меня; он научил меня, как использовать self-joins, чтобы получить max/min/something-n строк в группе.
в вашей ситуации он может быть применен к эффекту, который вы хотите так:
SELECT * FROM
(SELECT group, MAX(date) AS date FROM titles GROUP BY group)
AS x JOIN titles USING (group, date);
Я нашел эту тему через Google, похоже у меня тот же вопрос. Вот мое собственное решение, если, как и я, вам не нравятся подзапросы:
-- Create a temporary table like the output
CREATE TEMPORARY TABLE titles_tmp LIKE titles;
-- Add a unique key on where you want to GROUP BY
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`);
-- Read the result into the tmp_table. Duplicates won't be inserted.
INSERT IGNORE INTO titles_tmp
SELECT *
FROM `titles`
ORDER BY `date` DESC;
-- Read the temporary table as output
SELECT *
FROM titles_tmp
ORDER BY `group`;
Он имеет лучшую производительность. Вот как увеличить скорость, если date_column имеет тот же порядок, что и auto_increment_one (тогда вам не нужен оператор ORDER BY):
-- Create a temporary table like the output
CREATE TEMPORARY TABLE titles_tmp LIKE titles;
-- Add a unique key on where you want to GROUP BY
ALTER TABLE titles_tmp ADD UNIQUE KEY `group` (`group`);
-- Read the result into the tmp_table, in the natural order. Duplicates will update the temporary table with the freshest information.
INSERT INTO titles_tmp
SELECT *
FROM `titles`
ON DUPLICATE KEY
UPDATE `id` = VALUES(`id`),
`date` = VALUES(`date`),
`title` = VALUES(`title`);
-- Read the temporary table as output
SELECT *
FROM titles_tmp
ORDER BY `group`;
результат :
+----+-------+---------------------+---------+
| id | group | date | title |
+----+-------+---------------------+---------+
| 2 | 1 | 2012-07-26 19:01:20 | Title 2 |
| 5 | 2 | 2012-07-26 23:59:52 | Title 5 |
+----+-------+---------------------+---------+
на больших таблицах этот метод делает значительный момент с точки зрения производительности.
Ну, если даты уникальны в группе, это будет работать (если нет, вы увидите несколько строк, которые соответствуют максимальной дате в группе). (Кроме того, плохое именование столбцов, "группа", "дата" может дать вам синтаксические ошибки и такую специально "группу")
select t1.* from titles t1, (select group, max(date) date from titles group by group) t2
where t2.date = t1.date
and t1.group = t2.group
order by date desc
другой подход состоит в том, чтобы использовать пользовательские переменные MySQL для идентификации "перерыва управления" в group
значения.
если вы можете жить с дополнительный столбец возвращается, что-то вроде этого будет работать:
SELECT IF(s.group = @prev_group,0,1) AS latest_in_group
, s.id
, @prev_group := s.group AS `group`
, s.date
, s.title
FROM (SELECT t.id,t.group,t.date,t.title
FROM titles t
ORDER BY t.group DESC, t.date DESC, t.id DESC
) s
JOIN (SELECT @prev_group := NULL) p
HAVING latest_in_group = 1
ORDER BY s.group DESC
то, что это делает, упорядочивает все строки по group
и date
в порядке убывания. (Мы указываем DESC на всех Столбцах в порядке BY, в случае, если есть индекс на (group,date,id)
что MySQL может сделать "обратное сканирование". Включение id
столбец получает детерминированное (повторяющееся) поведение, в случае, когда существует более одной строки с последним date
значение.) Это встроенное представление с псевдонимами s
.
"трюк" мы используем, чтобы сравнить group
значение group
значением из предыдущей строки. Всякий раз, когда у нас есть другое значение, мы знаем, что мы начинаем "новую" группу, и что эта строка является "последней" строкой (у нас есть функция IF, возвращающая 1). В противном случае (когда значения группы совпадают), это не последняя строка (и у нас есть функция IF возвращает 0).
затем мы отфильтровываем все строки, у которых этого нет latest_in_group
установить как 1.
можно удалить этот дополнительный столбец, обернув этот запрос (как встроенное представление) в другой запрос:
SELECT r.id
, r.group
, r.date
, r.title
FROM ( SELECT IF(s.group = @prev_group,0,1) AS latest_in_group
, s.id
, @prev_group := s.group AS `group`
, s.date
, s.title
FROM (SELECT t.id,t.group,t.date,t.title
FROM titles t
ORDER BY t.group DESC, t.date DESC, t.id DESC
) s
JOIN (SELECT @prev_group := NULL) p
HAVING latest_in_group = 1
) r
ORDER BY r.group DESC
если id
поле является автоинкрементным полем, и можно с уверенностью сказать, что наибольшее значение id
поле также является самым высоким значением для date
любой группы, то это простое решение:
SELECT b.*
FROM (SELECT MAX(id) AS maxid FROM titles GROUP BY group) a
JOIN titles b ON a.maxid = b.id
ORDER BY b.date DESC
используйте ниже запрос mysql, чтобы получить последнюю обновленную/вставленную запись из таблицы.
SELECT * FROM
(
select * from `titles` order by `date` desc
) as tmp_table
group by `group`
order by `date` desc
используйте следующий запрос, чтобы получить самую последнюю запись из каждой группы
SELECT
T1.* FROM
(SELECT
MAX(ID) AS maxID
FROM
T2
GROUP BY Type) AS aux
INNER JOIN
T2 AS T2 ON T1.ID = aux.maxID ;
где ID-это поле автоматического приращения, а Type-тип записей,которые вы хотите сгруппировать.
MySQL использует немое расширение GROUP BY
что не является надежным, если вы хотите получить такие результаты, поэтому вы можете использовать
select id, group, date, title from titles as t where id =
(select id from titles where group = a.group order by date desc limit 1);
в этом запросе каждый раз, когда таблица сканируется полностью для каждой группы, чтобы найти самую последнюю дату. Я не мог найти лучшей альтернативы для этого. Надеюсь, это кому-то поможет.