这个FIRST_VALUE查询有什么问题?

时间:2009-08-04 17:39:11

标签: 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

并返回:

ID  TXT     D_USR   FIRST_ONE
450         3488    
449         3488    
79  A       3488    A
78  X       3488    A

这是预期的:

ID  TXT     ID_USR  FIRST_ONE
450         3488    A
449         3488    A
79  A       3488    A
78  X       3488    A

出了什么问题?为什么?

1 个答案:

答案 0 :(得分:7)

RANGE / ROWS的默认FIRST_VALUE(与任何其他分析函数一样)为BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

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

RANGE变为BETWEEEN UNBOUNDED PRECEDING AND CURRENT ROW EXCEPT FOR THE NULL ROWS(它不是有效的OVER条款。)

由于txt的{​​{1}} NULLid,因此首先选择它们,并且它们的范围为空,因为没有非NULL它们之间的行和UNBOUNDED PRECEDING

您应该更改查询的ORDER BYRANGE子句。

更改ORDER BY会将带有NULL id的行放到窗口的末尾,以便始终首先选择非NULL值(如果有),并{{1} 1}}将保证从该值开始:

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 重新定义范围以包括分区中的所有非RANGE行:

NULL