ORDER BY date и time ПЕРЕД НАЗНАЧЕНИЕМ GROUP BY в mysql
У меня есть таблица вроде этого:
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
(- > не работает!)
теперь он должен дать мне первый сумасшедший (имеет более раннюю дату), затем tom
но с GROUP BY name ORDER BY date ASC, time ASC
дает мне новый сумасшедший сначала, потому что он группирует, прежде чем он сортирует!
снова: проблема в том, что я не могу сортировать по дате и времени до группы i, потому что GROUP BY должна быть до ORDER BY!
Ответы
Ответ 1
Другой метод:
SELECT *
FROM (
SELECT *
ORDER BY date ASC, time ASC
) AS sub
GROUP BY name
Группы GROUP BY по первому совпадающему результату. Если этот первый совпадение попадает именно так, как вы хотите, все должно работать как ожидалось.
Я предпочитаю этот метод, поскольку подзапрос делает логический смысл, а не накладывает его на другие условия.
Ответ 2
Я думаю, это то, что вы ищете:
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'))
Ответ 3
Как мне не разрешено комментировать 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/
Ответ 4
Это сработало для меня:
SELECT *
FROM your_table
WHERE id IN (
SELECT MAX(id)
FROM your_table
GROUP BY name
);
Ответ 5
Используйте подзапрос:
select name, date, time
from mytable main
where date + time = (select min(date + time) from mytable where name = main.mytable)
order by date + time;
Ответ 6
У меня была другая вариация в этом вопросе, где у меня было только одно поле DATETIME
и мне понадобилось limit
после group by
или distinct
после сортировки по убыванию в соответствии с полем DATETIME
, но это что помогло мне:
select distinct (column) from
(select column from database.table
order by date_column DESC) as hist limit 10
В этом случае с полями split, если вы можете сортировать по concat, тогда вы можете уйти с чем-то вроде:
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
Ответ 7
Другой способ решить эту проблему - использовать 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
Подробнее об этом (а также о некоторых других способах достижения этой цели) можно прочитать на странице строк, содержащих максимум группы для определенного столбца.
Ответ 8
В Oracle это работает для меня
SELECT name, min(date), min(time)
FROM table_name
GROUP BY name
Ответ 9
Это не точный ответ, но это может быть полезно для людей, которые хотят решить какую-то проблему с подходом упорядочивания строк перед группировкой в mysql.
Я пришел к этой теме, когда мне захотелось найти последнюю строку (которая order by date desc
, но получить единственный результат для определенного типа столбца, который group by column name
),
Еще один подход к решению этой проблемы - использовать агрегацию.
Таким образом, мы можем разрешить выполнение запроса в обычном режиме, что отсортировало asc, и введем новое поле как max(doc) as latest_doc
, в котором будет указана самая последняя дата, с группировкой по одному столбцу.
Предположим, вы хотите найти данные определенного столбца сейчас, и максимальное агрегирование не может быть выполнено.
В общем, для поиска данных определенного столбца вы можете использовать GROUP_CONCAT aggregator
с некоторым уникальным разделителем, который не может присутствовать в этом столбце, например GROUP_CONCAT(string SEPARATOR ' ') as new_column
и пока вы получаете к нему доступ, вы можете разбить/разложить поле new_column.
Опять же, это может звучать не для всех. Я сделал это, и мне тоже понравилось, потому что я написал несколько функций и не мог запустить подзапросы. Я работаю над структурой codeigniter для php.
Не уверен в сложности, может быть, кто-то может пролить свет на это.
С уважением :)