这个FIRST_VALUE查询有什么问题?

Fer*_*anB 3 sql oracle

查询如下:

with t
as (
  select 450 id, null txt , 3488 id_usr from dual union all
  select 449   , null     , 3488        from dual union all
  select  79   , 'A'      , 3488        from dual union all
  select  78   , 'X'      , 3488        from dual 
)
select id
     , txt
     , id_usr
     , first_value(txt ignore nulls) over (partition by id_usr order by id desc) first_one
  from t
Run Code Online (Sandbox Code Playgroud)

并返回:

ID  TXT     D_USR   FIRST_ONE
450         3488    
449         3488    
79  A       3488    A
78  X       3488    A
Run Code Online (Sandbox Code Playgroud)

这是预期的:

ID  TXT     ID_USR  FIRST_ONE
450         3488    A
449         3488    A
79  A       3488    A
78  X       3488    A
Run Code Online (Sandbox Code Playgroud)

怎么了?为什么?

Qua*_*noi 7

默认RANGE / ROWSFIRST_VALUE(作为任何其它分析功能)是BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW.

如果添加IGNORE NULLS,则NULL在构建范围时不会考虑值.

RANGEBETWEEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCEPT FOR THE NULL ROWS(这不是一个有效的OVER条款).

因为你txt的那些是NULLid的,所以首先选择它们,并且它们的范围是空的,因为它们之间没有非NULL行和UNBOUNDED PRECEDING

您应该更改查询的任一ORDER BYRANGE子句.

更改ORDER BY将具有NULLid的行放入窗口的末尾,以便NULL始终首先选择非值(如果有),并且RANGE保证将从该值开始:

with t
as (
  select 450 id, null txt , 3488 id_usr from dual union all
  select 449   , null     , 3488        from dual union all
  select  79   , 'A'      , 3488        from dual union all
  select  78   , 'X'      , 3488        from dual 
)
select id
     , txt
     , id_usr
     , first_value(txt) over (partition by id_usr order by NVL2(TXT, NULL, id) DESC) first_one
  from t
Run Code Online (Sandbox Code Playgroud)

更改重RANGE定义范围以包括NULL分区中的所有非行:

with t
as (
  select 450 id, null txt , 3488 id_usr from dual union all
  select 449   , null     , 3488        from dual union all
  select  79   , 'A'      , 3488        from dual union all
  select  78   , 'X'      , 3488        from dual 
)
select id
     , txt
     , id_usr
     , first_value(txt IGNORE NULLS) over (partition by id_usr order by id DESC RANGE BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) first_one
  from t
Run Code Online (Sandbox Code Playgroud)