Как вы получаете строки, которые содержат максимальное значение для каждого сгруппированного набора?
Я видел некоторые слишком сложные варианты этого вопроса, но ни один из них не дал хорошего ответа. Я попытался собрать самый простой пример:
Учитывая приведенную ниже таблицу с столбцами персонажа, группы и возраста, как бы вы получили самого старого человека в каждой группе? (Галстук внутри группы должен дать первый алфавитный результат)
Person | Group | Age
---
Bob | 1 | 32
Jill | 1 | 34
Shawn| 1 | 42
Jake | 2 | 29
Paul | 2 | 36
Laura| 2 | 39
Требуемый набор результатов:
Shawn | 1 | 42
Laura | 2 | 39
mysql
sql
greatest-n-per-group
Ярина
источник
источник
Ответы:
Есть супер-простой способ сделать это в MySQL:
Это работает, потому что в mysql вам разрешено не агрегировать столбцы без группировки, и в этом случае mysql просто возвращает первую строку. Решение состоит в том, чтобы сначала упорядочить данные таким образом, чтобы для каждой группы сначала была указана нужная строка, а затем сгруппировать по столбцам, для которых необходимо получить значение.
Вы избегаете сложных подзапросов, которые пытаются найти
max()
etc, а также проблем с возвратом нескольких строк, когда существует более одной строки с одинаковым максимальным значением (как и другие ответы)Примечание: это решение только для mysql . Все другие известные мне базы данных будут выдавать синтаксическую ошибку SQL с сообщением «неагрегированные столбцы не перечислены в предложении group by» или аналогичными. Поскольку это решение использует недокументированное поведение, более осторожный может захотеть включить тест, чтобы утверждать, что он продолжает работать, если будущая версия MySQL изменит это поведение.
Обновление версии 5.7:
Начиная с версии 5.7,
sql-mode
настройка включаетONLY_FULL_GROUP_BY
по умолчанию, поэтому для этой работы у вас не должно быть этой опции (отредактируйте файл опции для сервера, чтобы удалить эту настройку).источник
SELECT
предложении и не вычисляется с использованием статистической функции.SELECT
предложении функционально не зависят отGROUP BY
столбцов. Если он настроен на его принятие (`ONLY_FULL_GROUP_BY` отключен), он работает так же, как и в предыдущих версиях (т.е. значения этих столбцов не определены).GROUP BY
сжимается до одной записи, но все поля будут произвольно выбраны из записей. Это может быть , что MySQL в настоящее время просто всегда выбирает первый ряд, но она могла бы точно так же выбрать любую другую строку или даже значение из разных строк в версии будущего.Правильное решение:
Как это устроено:
Он сопоставляет каждую строку
o
со всеми строками,b
имеющими одинаковое значение в столбцеGroup
и большее значение в столбцеAge
. Любая строка,o
не имеющая максимального значения своей группы в столбце,Age
будет соответствовать одной или нескольким строкам изb
.Он
LEFT JOIN
позволяет сопоставить самого старого человека в группе (включая лиц, которые одиноки в своей группе) с целой строкой изNULL
sb
(«не самый большой возраст в группе»).Использование
INNER JOIN
делает эти строки не совпадающими, и они игнорируются.Предложение
WHERE
сохраняет только строки, имеющиеNULL
s в полях, извлеченных изb
. Это самые старые люди в каждой группе.Дальнейшие чтения
Это решение и многие другие объясняются в книге « Антипаттерны SQL: предотвращение ловушек программирования баз данных».
источник
o.Age = b.Age
, например, если Пол из группы 2 находится на 39, как Лора. Однако, если мы не хотим такого поведения, мы можем сделать:ON o.Group = b.Group AND (o.Age < b.Age or (o.Age = b.Age and o.id < b.id))
Вы можете присоединиться к подзапросу, который тянет
MAX(Group)
иAge
. Этот метод является переносимым для большинства СУБД.источник
Group = 2, Age = 20
, подзапрос возвратил бы одну из них, но предложение соединения соответствовалоON
бы им обоим , поэтому вы получите 2 строки с одинаковой группой / возрастом, хотя разные значения для других столбцов, а не один.Мое простое решение для SQLite (и, вероятно, MySQL):
Однако это не работает в PostgreSQL и, возможно, на некоторых других платформах.
В PostgreSQL вы можете использовать предложение DISTINCT ON :
источник
Используя метод ранжирования.
источник
:=
- что это?Не уверен, что в MySQL есть функция row_number. Если это так, вы можете использовать его, чтобы получить желаемый результат. На SQL Server вы можете сделать что-то похожее на:
источник
Решение Axiac - то, что сработало для меня лучше всего в конце. Однако у меня была дополнительная сложность: вычисленное «максимальное значение», полученное из двух столбцов.
Давайте использовать тот же пример: я хотел бы, чтобы самый старый человек в каждой группе. Если есть люди одинаково старые, возьмите самого высокого человека.
Мне пришлось выполнить левое соединение два раза, чтобы получить такое поведение:
Надеюсь это поможет! Я думаю, что должен быть лучший способ сделать это, хотя ...
источник
Мое решение работает только в том случае, если вам нужно извлечь только один столбец, однако для моих нужд было найдено лучшее решение с точки зрения производительности (оно использует только один запрос!):
Он использует GROUP_CONCAT для создания упорядоченного списка конкатов, а затем я подстроку только к первому.
источник
У меня есть простое решение с помощью
WHERE IN
источник
Использование CTE - общие табличные выражения:
источник
В Oracle ниже запрос может дать желаемый результат.
источник
источник
Вы также можете попробовать
источник
Я бы не использовал Group в качестве имени столбца, так как это зарезервированное слово. Однако следующий SQL будет работать.
источник
Преимущество этого метода состоит в том, что вы можете ранжироваться по другому столбцу, а не уничтожать другие данные. Это очень полезно в ситуации, когда вы пытаетесь составить список заказов с колонкой для элементов, перечисляя самые тяжелые в первую очередь.
Источник: http://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html#function_group-concat
источник
пусть имя таблицы будет людьми
источник
Если ID (и все coulmns) необходимы из mytable
источник
Вот как я получаю N max строк на группу в MySQL
как это устроено:
co.country = ci.country
) < 1
так для 3 элементов -) <3co.id < ci.id
Полный пример здесь:
mysql выбрать n максимальных значений для группы
источник