Следующий запрос:
SELECT
year, id, rate
FROM h
WHERE year BETWEEN 2000 AND 2009
AND id IN (SELECT rid FROM table2)
GROUP BY id, year
ORDER BY id, rate DESC
выходы:
year id rate
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2009 p01 4.4
2002 p01 3.9
2004 p01 3.5
2005 p01 2.1
2000 p01 0.8
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
2006 p02 4.6
2007 p02 3.3
То, что я хотел бы, только лучшие 5 результатов для каждого идентификатора:
2006 p01 8
2003 p01 7.4
2008 p01 6.8
2001 p01 5.9
2007 p01 5.3
2001 p02 12.5
2004 p02 12.4
2002 p02 12.2
2003 p02 10.3
2000 p02 8.7
Есть ли способ сделать это, используя какой-нибудь LIMIT-подобный модификатор, который работает в GROUP BY?
sql
mysql
greatest-n-per-group
ranking
углубления
источник
источник
LIMIT
предложение. Вот статья, которая подробно объясняет проблему: Как выбрать первую / наименьшую / максимальную строку для каждой группы в SQL. Это хорошая статья - он представляет элегантное, но наивное решение проблемы «Top N на группу», а затем постепенно улучшается на этом.Ответы:
Вы можете использовать агрегированную функцию GROUP_CONCAT, чтобы получить все годы в одном столбце, сгруппированном
id
и упорядоченном поrate
:Результат:
И тогда вы можете использовать FIND_IN_SET , который возвращает позицию первого аргумента внутри второго, например.
Используя комбинацию
GROUP_CONCAT
иFIND_IN_SET
и фильтрацию по позиции, возвращаемой find_in_set, вы можете использовать этот запрос, который возвращает только первые 5 лет для каждого идентификатора:Пожалуйста, смотрите скрипку здесь .
Обратите внимание, что если несколько строк могут иметь одинаковую ставку, вам следует рассмотреть возможность использования GROUP_CONCAT (ставка DISTINCT ORDER BY) в столбце ставки вместо столбца года.
Максимальная длина строки, возвращаемой GROUP_CONCAT, ограничена, поэтому это хорошо работает, если вам нужно выбрать несколько записей для каждой группы.
источник
SET SESSION group_concat_max_len = <maximum length>;
В случае OP, не проблема (так как по умолчанию 1024), но в качестве примера, group_concat_max_len должно быть не менее 25: 4 (max длина строки года) + 1 (символ разделителя), умножить на 5 (первые 5 лет). Строки усечены, а не выдают ошибку, поэтому следите за предупреждениями, такими как1054 rows in set, 789 warnings (0.31 sec)
.FIND_IN_SET()
. Я пытался,FIND_IN_SET() =2
но не показывал результат, как ожидалось.Исходный запрос используется пользовательские переменные и
ORDER BY
на производных таблиц; поведение обеих причуд не гарантировано. Пересмотрен ответ следующим образом.В MySQL 5.x вы можете использовать звание бедного человека над разделом для достижения желаемого результата. Просто внешнее объедините таблицу с самим собой и для каждой строки посчитайте количество строк меньше ее. В приведенном выше случае меньшая строка - это та, которая имеет более высокую скорость:
Демо и результат :
Обратите внимание, что если ставки были связаны, например:
Приведенный выше запрос вернет 6 строк:
Перейдите на
HAVING COUNT(DISTINCT l.rate) < 5
8 строк:Или перейдите на
ON t.id = l.id AND (t.rate < l.rate OR (t.rate = l.rate AND t.pri_key > l.pri_key))
5 строк:В MySQL-или более поздняя версия просто использовать
RANK
,DENSE_RANK
илиROW_NUMBER
функцию:источник
WHERE rank <=5
? Впервые я не получаю 5 строк от каждого идентификатора, но после этого я могу получить, как вы сказали.SET
утверждение (см. Первый запрос). Это необходимо.ORDER BY
производная таблица может и часто будет игнорироваться. Это побеждает цель. Эффективные групповые найдены здесь .ORDER BY
в поставляемых / подзапросах подобного типа. Именно поэтому современные версии MySQL / MariaDB игнорируютORDER BY
входящий подзапрос без использованияLIMIT
, я полагаю, что стандарты ANSI / ISO SQL 2008/2011/2016 делаютORDER BY
в поставленных / подзапросах законными использование его в сочетании сFETCH FIRST n ROWS ONLY
Для меня что-то вроде
работает отлично. Нет сложного запроса.
например: получить топ 1 для каждой группы
источник
Нет, вы не можете произвольно ограничивать подзапросы (вы можете делать это в ограниченной степени в новых MySQL, но не для 5 результатов на группу).
Это запрос группового максимума, который нетривиально выполнять в SQL. Существуют различные способы решения этой проблемы, которые могут быть более эффективными в некоторых случаях, но для топ-н в целом вы захотите взглянуть на ответ Билла на аналогичный предыдущий вопрос.
Как и в большинстве решений этой проблемы, он может возвращать более пяти строк, если имеется несколько строк с одинаковым
rate
значением, поэтому вам может потребоваться некоторое количество постобработки, чтобы проверить это.источник
Для этого требуется ряд подзапросов для ранжирования значений, их ограничения, а затем для суммирования при группировании.
источник
Попробуй это:
источник
Подзапрос практически идентичен вашему запросу. Только изменение добавляет
источник
ROW_NUMBER()
).row_number()
это доступно .Построить виртуальные столбцы (например, RowID в Oracle)
Таблица:
данные:
SQL, как это:
если удалить предложение where в t3, оно выглядит так:
GET "TOP N Record" -> добавить "rownum <= 3" в предложении where (предложение where в t3);
ВЫБЕРИТЕ «год» -> добавьте «между 2000 и 2009» в предложении where (предложение where в t3);
источник
Потребовалось немного поработать, но я думаю, что мое решение будет чем-то, чем можно поделиться, поскольку оно кажется элегантным и довольно быстрым.
Обратите внимание, что этот пример указан для целей вопроса и может быть довольно легко изменен для других подобных целей.
источник
Следующий пост: sql: выбор топ-N записей для каждой группы описывает сложный способ достижения этого без подзапросов.
Это улучшает другие решения, предлагаемые здесь:
Это однако не красиво. Хорошее решение было бы достижимо, если бы в MySQL были включены оконные функции (или аналитические функции), но это не так. Уловка, использованная в упомянутом посте, использует GROUP_CONCAT, который иногда описывается как «Window Window Functions for MySQL».
источник
для таких как я, у которых были вопросы тайм-аут Я сделал ниже, чтобы использовать ограничения и все остальное определенной группой.
он перебирает список доменов, а затем вставляет только ограничение 200 каждый
источник
Попробуй это:
источник
Пожалуйста, попробуйте ниже хранимую процедуру. Я уже проверил. Я получаю правильный результат, но без использования
groupby
.источник