ЗАКАЗАТЬ ПО ДАТЕ И ВРЕМЕНИ ПЕРЕД ГРУППОВОЙ BY по имени в mysql - PullRequest
50 голосов
/ 04 июля 2011

У меня есть такая таблица:

name    date         time
tom | 2011-07-04 | 01:09:52
tom | 2011-07-04 | 01:09:52
mad | 2011-07-04 | 02:10:53
mad | 2009-06-03 | 00:01:01

сначала я хочу получить самое старое имя:

SELECT * 
ORDER BY date ASC, time ASC 
GROUP BY name

(-> не работает!)

теперь это должно дать мне сначала сумасшествие (имеет более раннюю дату), затем Том

но с GROUP BY name ORDER BY date ASC, time ASC дает мне сначала более нового сумасшедшего, потому что он группируется до сортировки!

еще раз: проблема в том, что я не могу отсортировать по дате и времени до того, как сгруппирую, потому что GROUP BY должна быть раньше ORDER BY!

Ответы [ 8 ]

71 голосов
/ 17 декабря 2012

Другой метод:

SELECT * 
FROM (
    SELECT * 
    ORDER BY date ASC, time ASC 
) AS sub
GROUP BY name

Группы GROUP BY для первого совпадения, которое он находит. Если это первое совпадение совпадения, которое вам нужно, тогда все должно работать как положено.

Я предпочитаю этот метод, так как подзапрос имеет логический смысл, а не дополняет его другими условиями.

26 голосов
/ 04 июля 2011

Я думаю, это то, что вы ищете:

SELECT name, min(date)
FROM myTable
GROUP BY name
ORDER BY min(date)

На данный момент вам нужно сделать дату mysql через STR_TO_DATE:

STR_TO_DATE(date + ' ' + time, '%Y-%m-%d %h:%i:%s')

Итак:

SELECT name, min(STR_TO_DATE(date + ' ' + time, '%Y-%m-%d %h:%i:%s'))
FROM myTable
GROUP BY name
ORDER BY min(STR_TO_DATE(date + ' ' + time, '%Y-%m-%d %h:%i:%s'))
23 голосов
/ 04 февраля 2016

Поскольку я не могу комментировать ответ пользователя user1908688, вот подсказка для пользователей MariaDB:

SELECT *
FROM (
     SELECT *
     ORDER BY date ASC, time ASC
     LIMIT 18446744073709551615
     ) AS sub
GROUP BY sub.name

https://mariadb.com/kb/en/mariadb/why-is-order-by-in-a-from-subquery-ignored/

8 голосов
/ 10 февраля 2017

Это сработало для меня:

SELECT *
FROM your_table
WHERE id IN (
    SELECT MAX(id)
    FROM your_table
    GROUP BY name
);
3 голосов
/ 04 июля 2011

Использовать подвыбор:

select name, date, time
from mytable main
where date + time = (select min(date + time) from mytable where name = main.mytable)
order by date + time;
0 голосов
/ 02 ноября 2018

Другим способом решения этой проблемы может быть LEFT JOIN, который может быть более эффективным. Сначала я начну с примера, который рассматривает только поле даты, поскольку, вероятно, более распространено хранить дату + время в одном столбце даты и времени, и я также хочу сделать запрос простым, чтобы его было легче понять.

Итак, в этом конкретном примере, если вы хотите показать самую старую запись, основанную на столбце date , и предполагая, что имя вашей таблицы называется people, вы можете использовать следующий запрос:

SELECT p.* FROM people p
LEFT JOIN people p2 ON p.name = p2.name AND p.date > p2.date
WHERE p2.date is NULL
GROUP BY p.name

Что делает LEFT JOIN, так это когда столбец p.date имеет минимальное значение, в левом соединении не будет p2.date с меньшим значением, и поэтому соответствующий p2.date будет NULL , Таким образом, добавляя WHERE p2.date is NULL, мы показываем только записи с самой старой датой.

И точно так же, если вы хотите вместо этого показать новейшую запись , вы можете просто изменить оператор сравнения в LEFT JOIN:

SELECT p.* FROM people p
LEFT JOIN people p2 ON p.name = p2.name AND p.date < p2.date
WHERE p2.date is NULL
GROUP BY p.name

Теперь, для этого конкретного примера, где дата + время являются отдельными столбцами, вам нужно будет каким-то образом добавить их, если вы хотите выполнить запрос на основе даты-времени двух столбцов, например:

SELECT p.* FROM people p
LEFT JOIN people p2 ON p.name = p2.name AND p.date + INTERVAL TIME_TO_SEC(p.time) SECOND > p2.date + INTERVAL TIME_TO_SEC(p2.time) SECOND
WHERE p2.date is NULL
GROUP BY p.name

Подробнее об этом (а также о некоторых других способах достижения этой цели) можно прочитать на строках, содержащих групповой максимум определенного столбца .

0 голосов
/ 17 мая 2018

Это не точный ответ, но он может быть полезен для людей, которые хотят решить какую-то проблему с подходом упорядочивания строк перед группировкой в ​​mysql.

Я пришел к этой теме, когда мне захотелось найти последнюю строку (которая равна order by date desc, но получить единственный результат для определенного типа столбца, который равен group by column name).

Еще один подход к решению этой проблемы - использовать использование агрегирования.

Таким образом, мы можем разрешить выполнение запроса в обычном режиме, что отсортировало asc , и введем новое поле как max(doc) as latest_doc, которое даст самую последнюю дату, с группировкой по той же самой колонка.

Предположим, вы хотите найти данные определенного столбца, и max агрегация не может быть выполнена. В общем, для поиска данных определенного столбца вы можете использовать GROUP_CONCAT aggregator с некоторым уникальным разделителем, который не может присутствовать в этом столбце, например GROUP_CONCAT(string SEPARATOR ' ') as new_column и пока вы получаете к нему доступ, вы можете разбить / разложить поле new_column.

Опять же, это может показаться не всем. Я сделал это, и мне тоже понравилось, потому что я написал несколько функций и не мог запустить подзапросы. Я работаю над структурой codeigniter для php.

Также не уверен в сложности, может кто-то может пролить свет на это.

С уважением:)

0 голосов
/ 21 июля 2017

У меня был другой вариант в этом вопросе, где у меня было только одно поле DATETIME, и мне нужно было limit после group by или distinct после сортировки по убыванию на основе поля datetime, но эточто мне помогло:

select distinct (column) from
(select column from database.table
order by date_column DESC) as hist limit 10

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

select name,date,time from
(select name from table order by concat(date,' ',time) ASC)
as sorted

Тогда, если вы хотите ограничить, вы просто добавите свое заявление об ограничении в конец:

select name,date,time from
(select name from table order by concat(date,' ',time) ASC)
as sorted limit 10
...