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     |
|------+-----------------+-------|

現在、2012-05-16 と 2012-05-18 の間の preformanceDate で結果セットを取得したいと考えています。現在の日付の値が 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" は読み取り専用であるため)、値を 1 つずつ更新する予定です。しかし、この方法は非常に遅いです。これについて何か考えはありますか?

4

2 に答える 2

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 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 に答える