在给定日期之间获得最高分数

时间:2016-09-06 18:17:10

标签: sql postgresql

有一个scores_score表,其中包含以下列:

id, player_name, value, created_at

我必须获得N(100)个最佳分数,其中:

  1. player_name在结果中必须是唯一的
  2. 仅返回给定player_name的最佳分数
  3. 结果必须按日期范围过滤
  4. 假设我有以下数据:

    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
    

    想要在2016-09-01和2016-09-20之间获得最佳分数。我应该得到:

    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 个答案:

答案 0 :(得分:3)

distinct on

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

答案 1 :(得分:1)

这将起作用,并将为您提供预期的输出。使用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日期不同,您会看到输出的差异: - )

答案 2 :(得分:0)

这个有点麻烦,但应该有用。首先选择日期范围内的玩家和值(a)。然后按球员(b)选择最高分数。然后加入id和日期(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