1

我以为我明白它是如何工作的,但现在我很困惑。

我有一个数据集:

id date     value
1  20080101 null
2  20090101 34
3  20100101 null

三条记录,分别是 2008 年 1 月、2009 年和 2010 年。现在我想用最新的非空值创建一个新列“value2”。基本上我想要一个具有 3 个 34 秒的 value2 列。我写的:

select id, date, value, first_value(value) ignore nulls over (order by date desc) as value2 from table

但是,我得到了:

id date     value   value2
1  20080101 null    34
2  20090101 34      34
3  20100101 null    null

最后一个值仍然是 null 而不是 34。这里出了什么问题?

4

3 回答 3

2

分析函数的默认窗口是,ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW如果您将其更改为,ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING那么您将获得所需的结果:

查询 1

WITH table_name AS (
            SELECT 1 AS id, TO_DATE( '20080101', 'YYYYMMDD' ) AS "date", NULL AS value FROM DUAL
  UNION ALL SELECT 2, TO_DATE( '20090101', 'YYYYMMDD' ), 34   FROM DUAL
  UNION ALL SELECT 3, TO_DATE( '20100101', 'YYYYMMDD' ), NULL FROM DUAL
)
SELECT id,
       "date",
       value,
       FIRST_VALUE( value IGNORE NULLS ) OVER (ORDER BY "date" DESC ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS value2
FROM   table_name;

结果

ID  | date                   | VALUE   | VALUE2
-------------------------------------------------
3   | 2010-01-01 00:00:00    | (null)  | 34
2   | 2009-01-01 00:00:00    | 34      | 34
1   | 2008-01-01 00:00:00    | (null)  | 34
于 2014-01-09T08:04:09.493 回答
0

你忘记了窗户。默认值为无界前行和当前行之间的范围,这意味着您的值正在从第一行到当前行的窗口中查找。您的排序行是:

id date     value
3  20100101 null
2  20090101 34
1  20080101 null
  • 对于 id 1,记录 3、2、1 是焦点。在这些的第二行中可以找到值 34。
  • 对于 id 2,记录 3、2 是焦点。在这些的第二行中可以找到值 34。
  • 对于 id 3,只有记录 3 是焦点。因此无法找到值 34。

顺便说一句:您的请求中有一个错字:它是 first_value(value ignore nulls),而不是 first_value(value) ignore nulls。

于 2014-01-09T07:24:39.990 回答
0

尝试消除 order by 子句中的空值

一个可能的解决方案可能是

with x as (
    select 1  as id , 20080101 as ddate , null as v from dual union all 
    select 2 , 20090101 ,34 from dual union all 
    select 3 , 20100101 ,null from dual union all 
    select 4 , 20090101 ,15 from dual union all 
    select 5 , 20110101 ,null from dual union all 
    select 6 , 20120101 ,null from dual union all 
    select 7 , 20030101 ,55 from dual
) 
select  x.* , 
    first_value(v) over (order by case when v is null then null else ddate end) as last_nn_v
from    x
order by ddate
/

        ID      DDATE          V  LAST_NN_V
---------- ---------- ---------- ----------
         7   20030101         55         55
         1   20080101                    55
         4   20090101         15         55
         2   20090101         34         55
         3   20100101                    55
         5   20110101                    55
         6   20120101                    55
于 2014-01-09T06:22:58.940 回答