代码之家  ›  专栏  ›  技术社区  ›  FerranB Tom

这个第一个值查询有什么问题?

  •  3
  • FerranB Tom  · 技术社区  · 15 年前

    查询如下:

    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 回复  |  直到 15 年前
        1
  •  7
  •   Quassnoi    15 年前

    违约 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 那是 无效的 有高 id 's,首先选择它们,它们的范围为空,因为没有- 无效的 它们之间的行和 UNBOUNDED PRECEDING

    你也应该换一个 ORDER BY 范围 查询的子句。

    改变 按顺序 将行与 无效的 身份证在窗口的末尾,这样- 无效的 值(如果有)将始终首先被选择,并且 范围 保证从该值开始:

    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
    

    改变 范围 重新定义范围以包括所有非- 无效的 分区中的行:

    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