我正在使用PostgreSQL编写SQL查询,需要对在某个位置"到达"的人进行排名.然而,不是每个人都到了.我使用rank()窗口函数来生成到达等级,但是在到达时间为空的地方,而不是返回空等级,rank()聚合函数只是将它们视为在其他人之后到达.我想要发生的是这些没有出现的排名NULL而不是这个估算的排名.
这是一个例子.假设我有一个如下所示的表dinner_show_up:
| Person | arrival_time | Restaurant |
+--------+--------------+------------+
| Dave | 7 | in_and_out |
| Mike | 2 | in_and_out |
| Bob | NULL | in_and_out |
Run Code Online (Sandbox Code Playgroud)
鲍勃从不露面.我写的查询将是:
select Person,
rank() over (partition by Restaurant order by arrival_time asc)
as arrival_rank
from dinner_show_up;
Run Code Online (Sandbox Code Playgroud)
结果将是
| Person | arrival_rank |
+--------+--------------+
| Dave | 2 |
| Mike | 1 |
| Bob | 3 |
Run Code Online (Sandbox Code Playgroud)
我想要发生的是这样的:
| Person | arrival_rank |
+--------+--------------+
| Dave | 2 |
| Mike | 1 |
| Bob | NULL |
Run Code Online (Sandbox Code Playgroud)
Gor*_*off 15
只需使用以下case声明rank():
select Person,
(case when arrival_time is not null
then rank() over (partition by Restaurant order by arrival_time asc)
end) as arrival_rank
from dinner_show_up;
Run Code Online (Sandbox Code Playgroud)
对于所有聚合函数(不仅是rank()),更通用的解决方案是在over()子句中通过'arrival_time is partition'进行分区.这将导致所有null arrival_time行被放入同一组并给定相同的排名,使非空行仅相对于彼此排名.
为了一个有意义的例子,我模拟了一个CTE,其行数比初始问题集多.请原谅宽行,但我认为他们更好地对比不同的技术.
with dinner_show_up("person", "arrival_time", "restaurant") as (values
('Dave' , 7, 'in_and_out')
,('Mike' , 2, 'in_and_out')
,('Bob' , null, 'in_and_out')
,('Peter', 3, 'in_and_out')
,('Jane' , null, 'in_and_out')
,('Merry', 5, 'in_and_out')
,('Sam' , 5, 'in_and_out')
,('Pip' , 9, 'in_and_out')
)
select
person
,case when arrival_time is not null then rank() over ( order by arrival_time) end as arrival_rank_without_partition
,case when arrival_time is not null then rank() over (partition by arrival_time is not null order by arrival_time) end as arrival_rank_with_partition
,case when arrival_time is not null then percent_rank() over ( order by arrival_time) end as arrival_pctrank_without_partition
,case when arrival_time is not null then percent_rank() over (partition by arrival_time is not null order by arrival_time) end as arrival_pctrank_with_partition
from dinner_show_up
Run Code Online (Sandbox Code Playgroud)
此查询为arrival_rank_with/without_partition提供相同的结果.但是,percent_rank()的结果确实不同:without_partition是错误的,范围从0%到71.4%,而with_partition正确地给出pctrank()范围从0%到100%.
同样的模式也适用于ntile()聚合函数.
它的工作原理是将所有空值与非空值分开,以便进行排名.这确保Jane和Bob被排除在0%到100%的百分位排名之外.
|person|arrival_rank_without_partition|arrival_rank_with_partition|arrival_pctrank_without_partition|arrival_pctrank_with_partition|
+------+------------------------------+---------------------------+---------------------------------+------------------------------+
|Jane |null |null |null |null |
|Bob |null |null |null |null |
|Mike |1 |1 |0 |0 |
|Peter |2 |2 |0.14 |0.2 |
|Sam |3 |3 |0.28 |0.4 |
|Merry |4 |4 |0.28 |0.4 |
|Dave |5 |5 |0.57 |0.8 |
|Pip |6 |6 |0.71 |1.0 |
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8812 次 |
| 最近记录: |