使用last not-null值更新有序行

Mar*_*rco 5 sql postgresql

考虑一个类似于以下数据的表

column_a (boolean) | column_order (integer)
TRUE               |     1
NULL               |     2
NULL               |     3
TRUE               |     4
NULL               |     5
FALSE              |     6
NULL               |     7
Run Code Online (Sandbox Code Playgroud)

我想编写一个查询,根据指定的顺序将每个NULL值替换为列的先前值中的column_a最后一个非NULLcolumn_order.结果应如下所示:

column_a (boolean) | column_order (integer)
TRUE               |     1
TRUE               |     2
TRUE               |     3
TRUE               |     4
TRUE               |     5
FALSE              |     6
FALSE              |     7
Run Code Online (Sandbox Code Playgroud)

为简单起见,我们可以假设第一个值永远不为空.如果连续NULL值不超过一个,则以下情况有效:

SELECT
  COALESCE(column_a, lag(column_a) OVER (ORDER BY column_order))
FROM test_table
ORDER BY column_order;
Run Code Online (Sandbox Code Playgroud)

但是,上述内容对于任意数量的连续NULL值都不起作用.什么是能够实现上述结果的Postgres查询?是否存在可以很好地扩展到大量行的高效查询?

Cra*_*ger 3

您可以使用一个方便的技巧,根据空序列和非空序列之间的划分来创建分区,然后sum将它们向前推进。casefirst_value

例如

select
  *,
  sum(case when column_a is not null then 1 else 0 end)
    OVER (order by column_order) as partition
from table1;

 column_a | column_order | partition 
----------+--------------+-----------
 t        |            1 |         1
          |            2 |         1
          |            3 |         1
 t        |            4 |         2
          |            5 |         2
 f        |            6 |         3
          |            7 |         3
(7 rows)
Run Code Online (Sandbox Code Playgroud)

然后

select
  first_value(column_a)
    OVER (PARTITION BY partition ORDER BY column_order),
  column_order
from (
    select
      *,
      sum(case when column_a is not null then 1 else 0 end)
        OVER (order by column_order) as partition
    from table1
) partitioned;
Run Code Online (Sandbox Code Playgroud)

给你:

 first_value | column_order 
-------------+--------------
 t           |            1
 t           |            2
 t           |            3
 t           |            4
 t           |            5
 f           |            6
 f           |            7
(7 rows)
Run Code Online (Sandbox Code Playgroud)