1

我不确定将问题称为“以前的有效值”是否合适。事情是这样的:

我有一个表“A”:

create table A (
  name varchar(16),
  performanceDate date,
  value int
);

name 和 PerformanceDate 都是主键。

有一个流程会每天为每个用户插入数据。因此,数据将如下所示:

select * from A;
|------+-----------------+-------|
| name | performanceDate | value |
|------+-----------------+-------|
| Joe  |      2012-05-18 | null  |
| Joe  |      2012-05-17 | 2     |
| Joe  |      2012-05-16 | null  |
| Joe  |      2012-05-15 | null  |
| Joe  |      2012-05-14 | 3     |
|------+-----------------+-------|

目前,我想获得一个 preformanceDate 介于 2012-05-16 和 2012-05-18 之间的结果集,如果当前日期的值为 null,则应将其替换为以前的有效值。例如,2012-05-16 的值为 null,2012-05-16 之前的第一个有效值为32012-05-14。因此,结果如下所示:

|------+-----------------+-------|
| name | performanceDate | value |
|------+-----------------+-------|
| Joe  |      2012-05-18 |     2 |
| Joe  |      2012-05-17 |     2 |
| Joe  |      2012-05-16 |     3 |
|------+-----------------+-------|

到目前为止,我打算先将数据插入到临时表中(因为表“A”对我来说是只读的),然后一个一个地更新值。但是这种方式非常慢。你对此有什么想法吗?

4

2 回答 2

2

您可以使用 LATERAL JOIN,SQLFiddle 上还没有 DB2,下面是它在 SQL Server 中的等价物。LATERAL 等价于 SQL Server 的 APPLY:

select x.name, x.performanceDate, coalesce(x.value, y.value) as value
from tbl x

outer apply 
( 
  -- find nearest

  select top 1 value
  from tbl
  where 

    x.value is null

    and 

    (
       name = x.name
       and value is not null 
       and performanceDate < x.performanceDate 
    )

  order by performanceDate desc

) as y
order by x.name, x.performanceDate desc

数据:

| NAME |            PERFORMANCEDATE |  VALUE |
|------|----------------------------|--------|
|  Joe | May, 18 2012 08:00:00-0700 | (null) |
|  Joe | May, 17 2012 08:00:00-0700 |      2 |
|  Joe | May, 16 2012 08:00:00-0700 | (null) |
|  Joe | May, 15 2012 08:00:00-0700 | (null) |
|  Joe | May, 14 2012 08:00:00-0700 |      3 |

输出:

| NAME |            PERFORMANCEDATE | VALUE |
|------|----------------------------|-------|
|  Joe | May, 18 2012 08:00:00-0700 |     2 |
|  Joe | May, 17 2012 08:00:00-0700 |     2 |
|  Joe | May, 16 2012 08:00:00-0700 |     3 |
|  Joe | May, 15 2012 08:00:00-0700 |     3 |
|  Joe | May, 14 2012 08:00:00-0700 |     3 |

现场测试:http ://www.sqlfiddle.com/#!6/e0158/8


基于 IBM 文档.. http://publib.boulder.ibm.com/infocenter/iseries/v7r1m0/index.jsp?topic=%2Fdb2%2Frbafztabref.htm

..,我希望是这样的:

select x.name, x.performanceDate, coalesce(x.value, y.value) as value
from tbl x,

lateral 
( 
  -- find nearest

  select top 1 value
  from tbl
  where 

    x.value is null

    and 

    (
       name = x.name
       and value is not null 
       and performanceDate < x.performanceDate 
    )

  order by performanceDate desc
  fetch first 1 rows only

) as y
order by x.name, x.performanceDate desc

关于 CROSS APPY/OUTER APPLY 的有趣指标:http: //explainextended.com/2009/07/16/inner-join-vs-cross-apply/

OUTER APPLY 的另一个使用示例:http ://www.ienablemuch.com/2012/04/outer-apply-walkthrough.html

于 2012-05-18T08:12:48.387 回答
0
with tmp1(name, performanceDate, value, cid) as (
select 
   name,
   performanceDate,
   value,
   count(value) over (partition by name 
                          order by performanceDate,
                                   value nulls last) as cid from A),
tmp2(name, performanceDate, value) as (
select 
   name,
   performanceDate,
   first_value(value) over (partition by name, cid 
                                order by performanceDate, 
                                         value nulls last from tmp1)
select * from tmp2;

with tmp1 (name, performanceDate_Begin, performanceDate_End, value) as (
select 
   name,
   performanceDate as performanceDate_Begin,
   lead(performanceDate) over (partition by name 
                                   order by performanceDate,
                                            value nulls last) as performanceDate_End,value from A where value is not null),
tmp2 (name, performanceDate, value) as (
select 
   A.name,
   A.performanceDate,
   tmp1.value 
from A 
left join tmp1 on A.name = B.name 
              and A.performanceDate >= tmp1.performanceDate_Begin 
              and A.performanceDate < coalesce(tmp1.performanceDate_End,date '9999-12-31'))
select * from tmp2
于 2013-06-24T12:04:51.507 回答