【问题标题】:order by doesn`t work in partition by clause in POSTGRESQL?order by 在 POSTGRESQL 中的 partition by 子句中不起作用?
【发布时间】:2021-06-03 04:31:49
【问题描述】:

我有一个这样的 postgresql 表:

我想用 id 来计算 cap = 0.0000 组的连续 dt 值,我试过这个:

select id ,dt,cap ,row_number() OVER ( partition by id,cap order by id,dt) t1 from tbl

我应该得到这样的结果:

id dt cap t1
10470 2020-12-01 00:00:00 0.0000 1
10470 2021-01-01 00:00:00 0.0000 2
10470 2021-02-01 00:00:00 0.0000 3
10470 2021-03-01 00:00:00 200.0000 1
10470 2021-04-01 00:00:00 0.0000 1
10470 2021-05-01 00:00:00 0.0000 2
10470 2021-06-01 00:00:00 0.0000 3

但实际上它的结果如下所示:

id dt cap t1
10470 2020-12-01 00:00:00 0.0000 1
10470 2021-01-01 00:00:00 0.0000 2
10470 2021-02-01 00:00:00 0.0000 3
10470 2021-04-01 00:00:00 0.0000 4
10470 2021-05-01 00:00:00 0.0000 5
10470 2021-06-01 00:00:00 0.0000 6
10470 2021-03-01 00:00:00 200.0000 1

如何得到我想要的结果?

【问题讨论】:

    标签: postgresql window-functions


    【解决方案1】:

    这是一个空白和孤岛问题。您想要的逻辑是,当我们在给定的id 记录块中遇到非零的cap 值时,行号序列应始终从 1 重新开始,按dt 列的顺序排列。

    解决此问题的一种方法是使用行数差异法:

    WITH cte1 AS (
        SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY dt) rn1,
                  ROW_NUMBER() OVER (PARTITION BY id,
                                     CASE WHEN cap < 0.0001 THEN 0 ELSE 1 END
                                     ORDER BY dt) rn2
        FROM tbl
    )
    
    SELECT id, dt, cap,
           ROW_NUMBER() OVER (PARTITION BY id, rn2-rn1 ORDER BY dt) AS t1
    FROM cte1
    ORDER BY id, dt;
    

    Demo

    这里的一条评论是,我正在使用以下CASE 表达式来检测cap 列中的零或非零:

    CASE WHEN cap < 0.0001 THEN 0 ELSE 1 END
    

    请注意,我将“零”定义为小于0.0001。原因是浮点值在 Postgres 中并不精确。因此,由于“零”cap 值并非完全为零,因此以下 CASE 表达式可能不会按预期运行:

    CASE WHEN cap = 0 THEN 0 ELSE 1 END
    

    【讨论】:

      猜你喜欢
      • 2019-03-21
      • 2011-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多