我有一个表,每个person_id
列有多个条目。我也存储了score
,category_id
和created
列。因此,每当该人完成指定的类别时,我都会为他们存储一条记录。
现在我尝试编写一个查询:只使用每个人最近创建的分数,找出有多少人得分比我对特定类别的得分更差。我这里基本上做了一个百分位计算。所以要获得我正在做的总分数:
select count(distinct person_id) from performances where category_id = 7;
我不知道怎么写第二个查询,但是发现有多少人做得比我差。这是在某个地方我会使用它吗?#34; OVER PARTITION"类型窗口函数?
答案 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
列表,没有重复的列。但如果每个(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
检查rank
,dense_rank
,percent_rank
,ntile
和cume_dist
:
http://www.postgresql.org/docs/current/static/functions-window.html
distinct on
会从每个person_id
返回一行。使用order by
子句可以选择每个子句。