Sql 什么';第一个值查询有什么问题?

Sql 什么';第一个值查询有什么问题?,sql,oracle,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 )

查询如下:

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

有什么问题以及原因?

对于
第一个值
(与任何其他分析函数一样)的默认
范围/行
在无界的前一行和当前行之间

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

范围
变为除空行(它不是有效的
OVER
子句)之外的无界前一行和当前行之间的

由于
txt
中的
NULL
具有较高的
id
,因此首先选择它们,并且它们的范围为空,因为它们之间没有非
NULL
行,并且
前面没有无界的

您应该更改查询的
orderby
RANGE
子句

通过
更改
顺序会将id为
NULL
的行置于窗口的末尾,以便始终首先选择非
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) over (partition by id_usr order by NVL2(TXT, NULL, id) DESC) first_one
  from t
更改
RANGE
会重新定义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

你的意思是“ignorenulls”子句不是用于确定“first_值”,而是用于窗口处理吗?@FerranB:不完全是。它从按
id
排序的范围中选择第一个非
NULL
值。如果在您的示例中,将
450
替换为
1
,它将为其选择“A”。我最好重写它,它现在很混乱。@Dave:它们都很重要。它将选择
NULL
作为
FIRST_值
,如果不是为
IGNORE NULLS
“当您指定IGNORE NULLS时,函数会忽略NULLS。”是的,但只确定第一个_值,而不是窗口。这对这个问题毫无意义。问题是,正如您所说,窗口是从当前行开始的,而不是从所有分区行开始的。