PostgreSQL last_value忽略null

时间:2019-06-23 22:13:12

标签: sql postgresql null window-functions

我知道已经有人问过这个问题,但是为什么下面的解决方案不起作用?我想用value排序的最后一个非空值填充idx

我所看到的:

 idx | coalesce 
-----+----------
   1 |        2
   2 |        4
   3 |         
   4 |         
   5 |       10
(5 rows)

我想要什么:

 idx | coalesce 
-----+----------
   1 |        2
   2 |        4
   3 |        4 
   4 |        4 
   5 |       10
(5 rows)

代码:

with base as (

    select 1    as idx
         , 2    as value

    union

    select 2    as idx
         , 4    as value

    union

    select 3    as idx
         , null as value

    union

    select 4    as idx
         , null as value

    union

    select 5    as idx
         , 10   as value
)

select idx
     , coalesce(value
              , last_value(value) over (order by case when value is null then -1
                                                 else idx
                                                 end))
from base
order by idx

3 个答案:

答案 0 :(得分:1)

要了解为什么您的解决方案不起作用,请按照窗口框架中的顺序查看输出:

with base as (
    select 1    as idx
         , 2    as value
    union
    select 2    as idx
         , 4    as value
    union
    select 3    as idx
         , null as value
    union
    select 4    as idx
         , null as value
    union
    select 5    as idx
         , 10   as value
)
select idx, value from base
order by case when value is null then -1
                                                 else idx
                                                 end;
 idx | value
-----+-------
   3 |
   4 |
   1 |     2
   2 |     4
   5 |    10

last_value()窗口函数将选择当前帧中的最后一个值。在不更改任何框架默认值的情况下,这将是当前行。

答案 1 :(得分:1)

您想要的是lag(ignore nulls)。这是使用两个窗口函数来执行所需操作的一种方法。第一个定义NULL值的分组,第二个分配值:

select idx, value, coalesce(value, max(value) over (partition by grp))
from (select b.*, count(value) over (order by idx) as grp
      from base b
     ) b
order by idx;

您也可以通过使用数组来执行此操作而无需子查询。基本上,取最后一个元素不计算NULL

select idx, value, 
       (array_remove(array_agg(value) over (order by idx), null))[count(value) over (order by idx)]
from base b
order by idx;

Here是db <>小提琴。

答案 2 :(得分:1)

除非您可以指出我的意思,否则这里的last_value对我没有意义。查看示例,您需要最后一个非值,可以通过以下方法获取它: 我正在用空值和先前的非空值组成一个组,以便获得第一个非值。

with base as (
select 1    as idx , 2    as value   union
select 2    as idx, -14    as value    union
select 3    as idx , null as value   union
select 4    as idx , null as value   union
select 5    as idx , 1   as value
)
Select idx,value,
first_value(value) Over(partition by rn) as new_val
from(
select idx,value
    ,sum(case when value is not null then 1 end) over (order by idx) as rn
  from   base
) t

这是代码

http://sqlfiddle.com/#!15/fcda4/2