选择最大项目数,获得排名和百分位数

时间:2014-08-08 19:05:14

标签: sql postgresql greatest-n-per-group window-functions percentile

我有一个表,每个person_id列有多个条目。我也存储了scorecategory_idcreated列。因此,每当该人完成指定的类别时,我都会为他们存储一条记录。

现在我尝试编写一个查询:只使用每个人最近创建的分数,找出有多少人得分比我对特定类别的得分更差。我这里基本上做了一个百分位计算。所以要获得我正在做的总分数:

select count(distinct person_id) from performances where category_id = 7;

我不知道怎么写第二个查询,但是发现有多少人做得比我差。这是在某个地方我会使用它吗?#34; OVER PARTITION"类型窗口函数?

2 个答案:

答案 0 :(得分:3)

实际要求的内容

  

仅为每个人使用最近创建的分数

...转换为:

SELECT DISTINCT ON (person_id) *
FROM   performances
ORDER  BY person_id, created DESC;

在此处(尚未)添加WHERE条件,否则会得到不同(不正确)的结果。 DISTINCT ON 的详细信息:

  

了解有多少人得分比我在特定类别中的得分差。

...转换为:

SELECT *
     , dense_rank() OVER w AS worse_than_me
     , ntile(100)   OVER w AS percentile
FROM  (
   SELECT DISTINCT ON (person_id) *
   FROM   performances
   ORDER  BY person_id, created DESC
  ) p
WINDOW w AS (PARTITION BY category_id ORDER BY score);

假设"更糟糕"表示较低的分数 window function dense_rank()是回答问题的正确工具"有多少人?" - 而不是rank()回答"有多少不同的分数?"。

ntile(100)在相同的窗口定义中为您提供了就绪百分位数为整数,100表示在前1%中,99表示在第二个最佳%等中。

但是,ntile()会返回per documentation

  

整数范围从1到参数值,除以分区   尽可能平等

这意味着,如果您的分区中的行数少于100行(如您所评论的那样),请按100.0 / count(*)多个来缩放数字。 A"百分位"对于一组完整的行来说,它不是最有用的统计信息,它通常用于集。

你没有问我

但很有可能要问:

"每个人如何在该类别中所有其他结果中最后完成的类别中排名?"

假设(person_id, category_id)唯一条目,或者您还必须定义如何处理同一类别(包括自己)中每个人的多个结果。

SELECT *
FROM  (
   SELECT DISTINCT ON (person_id) *
   FROM   performances
   ORDER  BY person_id, created DESC
   ) pers
JOIN (
   SELECT person_id, category_id
        , dense_rank() OVER w AS worse_than_me
        , ntile(100)   OVER w AS percentile
   FROM   performances
   WINDOW w AS (PARTITION BY category_id ORDER BY score)
   ) rnk f USING (person_id, category_id);
  • 在子查询pers中,我们提取每人最后一个条目(感兴趣的条目)。
  • 在子查询rnk中,与所有其他条目相比,我们获得了排名和百分位数。
  • JOIN带有USING子句,您有一个准备好的SELECT列表,没有重复的列。

你没有问过II

但如果每个(person_id, category_id)可以有多个条目,那么也会更有意义:

"获取每个类别中每个人的最新分数与同一类别中所有其他最新个人分数的排名。"

SELECT *
     , dense_rank() OVER w AS worse_than_me
     , ntile(100)   OVER w AS percentile
FROM  (
   SELECT DISTINCT ON (person_id, category_id) *
   FROM   performances
   ORDER  BY person_id, category_id, created DESC;
  ) p
WINDOW w AS (PARTITION BY category_id ORDER BY score);

不明确/含糊不清的问题导致任意结果。解决方案的第一步是明确定义任务

答案 1 :(得分:1)

select
    person_id,
    count(*) over() as total_person,
    rank() over(order by score desc) as score_rank
from (
    select distinct on (person_id) *
    from score
    where category_id = 7
    order by person_id, created desc
) s

检查rankdense_rankpercent_rankntilecume_dist

http://www.postgresql.org/docs/current/static/functions-window.html

distinct on会从每个person_id返回一行。使用order by子句可以选择每个子句。