【问题标题】:How to rank in postgres query如何在 postgres 查询中排名
【发布时间】:2012-04-22 04:31:01
【问题描述】:

我正在尝试对表中的数据子集进行排名,但我认为我做错了什么。我找不到有关 postgres 的 rank() 功能的太多信息,也许我找错了地方。无论哪种方式:

我想知道某个 id 在基于日期的表集群中的排名。我的查询如下:

select cluster_id,feed_id,pub_date,rank 
from (select feed_id,pub_date,cluster_id,rank() 
    over (order by pub_date asc) from url_info) 
as bar where cluster_id = 9876 and feed_id = 1234;

我在以下 stackoverflow 帖子之后对此进行建模:postgres rank

我认为我做错了什么的原因是 url_info 中只有 39 行位于 cluster_id 9876 中,并且此查询运行了 10 分钟并且再也没有回来。 (实际上重新运行了很长一段时间,它没有返回任何结果,但是在集群 9876 中有一行 id 1234)我期待这会告诉我“id 1234 在给定的标准中排名第五)。它会根据我的查询约束返回一个相对排名,对吗?

这是 postgres 8.4 顺便说一句。

【问题讨论】:

  • 你想要排名相对于什么?所有记录(这是您上面的查询所要求的,可能是为什么需要太长时间)?谓词选择的记录集?其他一些分组?如果您不想对所有行进行排名,over 子句应指定 partition byHere's the tutorial on window functions
  • 我想相对于 pub_date 进行排名。也许我可以解释得更好一点: url_info 里面有数千个 url。其中 39 个组成集群 9876。通过仅选择属于 9876 的 url(url 只能是一个集群的成员),我想根据 pub_date 按顺序对 url(组成集群 9876)进行排名。我仍然为此使用基于窗口函数的分区吗?我查看了您发送的 URL,看起来这是指在我计算一些值之后对项目进行排名,我在这里没有这样做....

标签: postgresql


【解决方案1】:

通过将 rank() 函数放置在子选择中,而不是在 over 子句中指定 PARTITION BY 或在该子选择中指定任何谓词,您的查询要求对按 pub_date 排序的整个 url_info 表产生排名。这可能就是为什么它运行了这么久才能对所有 url_info 进行排序,Pg 必须按 pub_date 对整个表进行排序,如果表很大,这将需要一段时间。

您似乎只想为 where 子句选择的记录集生成排名,在这种情况下,您需要做的就是消除子选择,排名函数隐含地覆盖与该谓词匹配的记录集。

select 
  cluster_id
 ,feed_id
 ,pub_date
 ,rank() over (order by pub_date asc) as rank
from url_info
where cluster_id = 9876 and feed_id = 1234;

如果您真正想要的是集群中的排名,无论 feed_id 是什么,您都可以在子选择中对哪些过滤器对该集群进行排名:

select ranked.*
from (
  select 
    cluster_id
   ,feed_id
   ,pub_date
   ,rank() over (order by pub_date asc) as rank
  from url_info
  where cluster_id = 9876
) as ranked
where feed_id = 1234;

【讨论】:

  • rank() over (order by pub_date asc) as rank 是多余的,因为默认的列名是函数名
  • @isapir 也许是这样,但这不是一个强有力的承诺;来自docs:“在更复杂的情况下,可能会使用函数或类型名称,或者系统可能会依赖生成的名称,例如 ?column?”
【解决方案2】:

分享另一个 PostgreSQL 的 DENSE_RANK() 例子。 查找前 3 名学生示例查询。 Reference taken from this blog:

使用示例数据创建表格:

CREATE TABLE tbl_Students
(
    StudID INT
    ,StudName CHARACTER VARYING
    ,TotalMark INT
);

INSERT INTO tbl_Students 
VALUES 
(1,'Anvesh',88),(2,'Neevan',78)
,(3,'Roy',90),(4,'Mahi',88)
,(5,'Maria',81),(6,'Jenny',90);

使用 DENSE_RANK(),计算学生的排名:

;WITH cteStud AS
(
    SELECT 
        StudName
        ,Totalmark
        ,DENSE_RANK() OVER (ORDER BY TotalMark DESC) AS StudRank
    FROM tbl_Students
)
SELECT 
    StudName
    ,Totalmark
    ,StudRank
FROM cteStud 
WHERE StudRank <= 3;

结果:

studname | totalmark | studrank
----------+-----------+----------
 Roy      |        90 |        1
 Jenny    |        90 |        1
 Anvesh   |        88 |        2
 Mahi     |        88 |        2
 Maria    |        81 |        3
(5 rows)

【讨论】:

  • 我认为值得指出的是,dense_rank() 产生的排名没有差距(1,1,2,3,4,5,5,5,6,7 ,...),而 rank() 产生有间隙的排名 (1,1,3,4,5,5,7,...)
猜你喜欢
  • 2010-10-05
  • 1970-01-01
  • 2017-07-23
  • 1970-01-01
  • 1970-01-01
  • 2021-05-04
  • 1970-01-01
  • 1970-01-01
  • 2014-03-05
相关资源
最近更新 更多