PostgreSQL窗口函数排序

时间:2016-02-09 16:32:29

标签: sql postgresql window-functions gaps-and-islands

我有这张桌子(PostgreSQL 9.3):

x | y  
- | -  
1 | 1  
2 | 2  
2 | 3  
1 | 4

现在我尝试从中获取三个分区:每次x值发生变化时(通过排序y),都应该给出一个新的dense_rank值。现在我尝试了以下内容:

SELECT x, y, dense_rank() over (partition by x order by y) 
FROM table

但是对于x上的分区,排序并不像我期望的那样工作。结果是

x  y  dense_rank  
-  -  ----------  
1  1  1     
1  4  2     
2  2  1     
2  3  2 

而不是预期的:

x  y  dense_rank  
-  -  ----------  
1  1  1     
2  2  2     
2  3  2     
1  4  3 

现在我不确定为什么窗口没有被y命令。

在第二步中,我需要这个分组进行分组(GROUP BY dense_rank,x)。所以最后我需要以下结果:

x  y      dense_rank  
-  -      ----------  
1  1      1     
2  {2,3}  2         
1  4      3 

也许这可以通过更简单的方式实现?

1 个答案:

答案 0 :(得分:3)

  

在x上进行分区,排序不按我期望的方式工作

它工作得非常好。当您按x分区1并且最后1位于同一组中时。

  

Window Functions

     

OVER中的PARTITION BY列表指定将行划分为共享相同PARTITION BY表达式值的组或分区。对于每一行,窗口函数是在与当前行属于同一分区的行中计算的。

要获得您想要的结果(间隙和岛屿问题的经典示例):

SELECT *, ROW_NUMBER() OVER (ORDER BY y) -
          ROW_NUMBER() OVER (PARTITION BY x ORDER BY y) + 1 AS group_id
FROM tab
ORDER BY group_id

LiveDemo

输出:

╔═══╦═══╦══════════╗
║ x ║ y ║ group_id ║
╠═══╬═══╬══════════╣
║ 1 ║ 1 ║        1 ║
║ 2 ║ 2 ║        2 ║
║ 2 ║ 3 ║        2 ║
║ 1 ║ 4 ║        3 ║
╚═══╩═══╩══════════╝

警告:
这个解决方案并不通用。

修改

更一般的解决方案是利用LAG获取以前的值并加窗SUM

WITH cte AS
(
  SELECT t1.x, t1.y, LAG(x) OVER(ORDER BY y) AS x_prev
  FROM tab t1
)
SELECT x,y, SUM( CASE WHEN x = COALESCE(x_prev,x) THEN 0 ELSE 1 END) 
            OVER(ORDER BY y) + 1 AS group_id
FROM cte
ORDER BY group_id;

LiveDemo2