2016-06-01 11 views
0

を探す:Oracleは - 私は2つのテーブルを持っている最も近い値と日付の違い

table1 

user start   end   parameter 
1  1 jan 2010 31 mar 2010 abc 
1  1 apr 2010 30 jun 2010 abc 
1  1 jan 2010 31 mar 2010 xyz 
1  1 apr 2010 30 jun 2010 xyz 
1  1 jan 2010 31 mar 2010 qqq 
1  1 apr 2010 30 jun 2010 qqq 

table2 

start   end   parameter value 
1 jan 2009 31 mar 2009 abc  100 
1 apr 2009 30 jun 2009 abc  200 
1 jan 2009 31 mar 2009 xyz  300 
1 apr 2009 30 jun 2009 xyz  400 
1 jan 2009 31 mar 2009 qqq  500 
1 apr 2009 30 jun 2009 qqq  600 

私は、パラメータに基づいて2つのテーブルを関連付ける開始および終了する必要があります。私は最も近い値を見つける必要があります。だから、元気です。 2010年1月1日〜2010年3月31日のパラメータabcでは、table2に値がありません。したがって、最も近い値を取得します。つまり、2009年1月1日から2009年6月30日までのパラメータabcおよび関連する値200を取得します。両方のテーブルの開始から。

結果のテーブルには次のようになります。

表3:

user start   end   parameter value diff 
1  1 jan 2010 31 mar 2010 abc  200  270 days 
1  1 apr 2010 30 jun 2010 abc  200  365 days 
1  1 jan 2010 31 mar 2010 xyz  400  270 days 
1  1 apr 2010 30 jun 2010 xyz  400  365 days 
1  1 jan 2010 31 mar 2010 qqq  600  270 days 
1  1 apr 2010 30 jun 2010 qqq  600  365 days 
+0

このデータは、実際には同じテーブル内のすべてではなく、2つの異なるテーブルにありますか? – Boneist

+0

どうすれば 'nearest'を定義していますか?table1の終わりより前に終了する最新のtable2?あるいは、それが古いものよりも早く始まったならば、将来の記録は許されるでしょう - そしてもし彼らが結ばれたらどうなりますか? –

+0

@Boneist - 彼らは別のテーブルにあります – dang

答えて

2

ここに1つの方法です:

with table1 as (select 1 usr, to_date('01/01/2010', 'dd/mm/yyyy') start_date, to_date('31/03/2010', 'dd/mm/yyyy') end_date, 'abc' parameter from dual union all 
       select 1 usr, to_date('01/04/2010', 'dd/mm/yyyy') start_date, to_date('30/06/2010', 'dd/mm/yyyy') end_date, 'abc' parameter from dual union all 
       select 1 usr, to_date('01/01/2010', 'dd/mm/yyyy') start_date, to_date('31/03/2010', 'dd/mm/yyyy') end_date, 'xyz' parameter from dual union all 
       select 1 usr, to_date('01/04/2010', 'dd/mm/yyyy') start_date, to_date('30/06/2010', 'dd/mm/yyyy') end_date, 'xyz' parameter from dual union all 
       select 1 usr, to_date('01/01/2010', 'dd/mm/yyyy') start_date, to_date('31/03/2010', 'dd/mm/yyyy') end_date, 'qqq' parameter from dual union all 
       select 1 usr, to_date('01/04/2010', 'dd/mm/yyyy') start_date, to_date('30/06/2010', 'dd/mm/yyyy') end_date, 'qqq' parameter from dual), 
    table2 as (select 1 usr, to_date('01/01/2009', 'dd/mm/yyyy') start_date, to_date('31/03/2009', 'dd/mm/yyyy') end_date, 'abc' parameter, 100 value from dual union all 
       select 1 usr, to_date('01/04/2009', 'dd/mm/yyyy') start_date, to_date('30/06/2009', 'dd/mm/yyyy') end_date, 'abc' parameter, 200 value from dual union all 
       select 1 usr, to_date('01/01/2009', 'dd/mm/yyyy') start_date, to_date('31/03/2009', 'dd/mm/yyyy') end_date, 'xyz' parameter, 300 value from dual union all 
       select 1 usr, to_date('01/04/2009', 'dd/mm/yyyy') start_date, to_date('30/06/2009', 'dd/mm/yyyy') end_date, 'xyz' parameter, 400 value from dual union all 
       select 1 usr, to_date('01/01/2009', 'dd/mm/yyyy') start_date, to_date('31/03/2009', 'dd/mm/yyyy') end_date, 'qqq' parameter, 500 value from dual union all 
       select 1 usr, to_date('01/04/2009', 'dd/mm/yyyy') start_date, to_date('30/06/2009', 'dd/mm/yyyy') end_date, 'qqq' parameter, 600 value from dual) 
-- end of mimicking your tables; see SQL below: 
select usr, 
     start_date, 
     end_date, 
     parameter, 
     latest_value, 
     diff_days 
from (select usr, 
       start_date, 
       end_date, 
       parameter, 
       last_value(value ignore nulls) over (partition by usr, parameter order by start_date) latest_value, 
       start_date - last_value(case when value is not null then start_date end ignore nulls) over (partition by usr, parameter order by start_date) diff_days 
     from (select usr, 
         start_date, 
         end_date, 
         parameter, 
         cast(null as number) value 
       from table1 
       union all 
       select usr, 
         start_date, 
         end_date, 
         parameter, 
         value 
       from table2)) 
where diff_days > 0; 

     USR START_DATE END_DATE PARAMETER LATEST_VALUE DIFF_DAYS 
---------- ----------- ----------- --------- ------------ ---------- 
     1 01 jan 2010 31 mar 2010 abc    200  275 
     1 01 apr 2010 30 jun 2010 abc    200  365 
     1 01 jan 2010 31 mar 2010 qqq    600  275 
     1 01 apr 2010 30 jun 2010 qqq    600  365 
     1 01 jan 2010 31 mar 2010 xyz    400  275 
     1 01 apr 2010 30 jun 2010 xyz    400  365 

これは、最新のnull以外の値を見つけるために分析関数last_value()を使用していますが、値とそれに対応するend_dateを計算し、その後、必要な減算を行って、後の期間と最新の有効期間の開始との間の差を取得する 日付。

N.B.これは、両方のテーブルに期間が重複していないことを前提としています。

関連する問題