Oracle - 查找最接近的值和日期差异

时间:2016-06-01 15:52:50

标签: sql oracle

我有两张桌子:

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年4月1日至2009年3月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

1 个答案:

答案 0 :(得分:2)

这是一种方式:

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

这使用分析函数last_value()来查找值的最新非空值及其对应的end_date,然后进行必要的减法以获得后期和最新可用期间的开始之间的差异日期。

N.B。这假设两个表之间没有重叠的句点。