我不确定将问题称为“之前的有效值”是否合适。事情如下:
我有一张桌子“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 |
|------+-----------------+-------|
目前,我想在2012-05-16和2012-05-18之间获得preformanceDate的结果集如果当前日期的值为null,则应将其替换为之前的vaild值。例如,2012-05-16的值为null,2012-05-16之前的第一个有效值为2012-05-14的3
。所以,结果如下:
|------+-----------------+-------|
| name | performanceDate | value |
|------+-----------------+-------|
| Joe | 2012-05-18 | 2 |
| Joe | 2012-05-17 | 2 |
| Joe | 2012-05-16 | 3 |
|------+-----------------+-------|
到目前为止,我计划首先将数据插入临时表(因为表“A”只为我读取),然后逐个更新值。但这种方式很慢。你对此有什么想法吗?
答案 0 :(得分:2)
您可以使用LATERAL JOIN,DB2尚未在SQLFiddle上,以下是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的有趣指标:http://explainextended.com/2009/07/16/inner-join-vs-cross-apply/
使用OUTER APPLY的另一个例子:http://www.ienablemuch.com/2012/04/outer-apply-walkthrough.html
答案 1 :(得分: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