Существует таблица scores_score
, которая содержит следующие столбцы:
id, player_name, value, created_at
Мне нужно получить N (100) лучших результатов, где:
- player_name должно быть уникальным для всех результатов
- должен быть возвращен только лучший результат для данного player_name
- результаты должны быть отфильтрованы по диапазону дат
Допустим, у меня есть следующие данные:
id player_name value date
1 A 400 2016-09-10
2 B 200 2016-09-12
3 C 400 2016-09-15
4 C 500 2016-09-14
5 B 100 2016-09-20
6 A 6000 2015-01-01
7 B 1200 2016-09-29
И хотим показать лучших игроков с их результатами в период с 01.09.2016 по 20.09.2016. Я должен получить:
id player_name value date
4 C 500 2016-09-14
1 A 400 2016-09-10
2 B 200 2016-09-12
Это мой подход к ее решению, но есть проблема во вложенном SELECT, поскольку он получает лучший результат игрока в целом за пределами диапазона дат.
SELECT b.*, a.*
FROM (SELECT player_name, max(value) AS max_value
FROM scores_score
GROUP BY player_name
ORDER BY max(value) DESC) a
INNER JOIN scores_score b ON a.player_name = b.player_name AND a.max_value = b.value
WHERE CAST(b.created_at AS DATE) >= %(date_border)s
ORDER BY b.value DESC
LIMIT 100
3 ответа
select *
from (
select distinct on (player_name) *
from scores_score
where date between '2016-09-01' and '2016-09-20'
order by player_name, value desc
) s
order by value desc
limit 100
Это сработает и даст вам ожидаемый результат. Используйте оконную функцию row_number()
, чтобы отметить наивысший результат для каждого игрока между датами (rn = 1
), а затем упорядочите набор результатов по value
по убыванию и, наконец, ограничьте вывод до 100 наивысших.
select
id, player_name, value, created_at
from (
select
id, player_name, value, created_at,
row_number() over (partition by player_name order by value desc, id) as rn
from scores_score
where created_at between '2016-09-01' and '2016-09-20'
) ranks
where rn = 1
order by value desc
limit 100
Обратите внимание, что дополнительный столбец id
для сортировки в функции row_number
предназначен для разрешения связей (даже если он назначает только одно значение для каждой строки в разделе), в которых один и тот же игрок имеет две строки с равными значениями, которые находятся в пределах заданная дата. Это будет более старая запись, и если они отличаются датой created_at
, вы увидите разницу в выводе :-)
Это немного громоздко, но должно работать. Сначала выберите только игроков и значения в пределах вашего диапазона дат (а). Затем выберите максимальное количество очков по игроку (b). Затем присоедините идентификатор и дату (c):
SELECT c.id, c.player_name, c.value, c.date
FROM
scores_score c
INNER JOIN
(SELECT player_name, max(value)
FROM
(SELECT player_name, value
FROM scores_score
WHERE date BETWEEN '2016-09-01' AND '2016-09-20') a
GROUP BY player_name) b
ON c.player_name = b.player_name
AND c.value = b.value
ORDER BY value
LIMIT 100
Протестировано здесь: http://sqlfiddle.com/#!9/10db42/6
Похожие вопросы
Новые вопросы
sql
Язык структурированных запросов (SQL) - это язык запросов к базам данных. Вопросы должны включать примеры кода, структуру таблицы, примеры данных и тег для используемой реализации СУБД (например, MySQL, PostgreSQL, Oracle, MS SQL Server, IBM DB2 и т. Д.). Если ваш вопрос относится исключительно к конкретной СУБД (использует определенные расширения / функции), используйте вместо этого тег этой СУБД. Ответы на вопросы, помеченные SQL, должны использовать стандарт ISO / IEC SQL.