如何编写查询以显示两个日期之间的月份?

时间:2016-05-12 16:24:51

标签: sql oracle

我有一个带有收入和开始/结束日期的ID数据库,如下所示,但我无法打破给定开始/结束日期范围内每个ID每月的收入。

表格数据的样本如下:

ID | INCOME | MONTH
 1 |   2000 | 05/2016
 1 |   2000 | 04/2016
 1 |   2000 | 03/2016
 1 |   2000 | 02/2016
 1 |   1500 | 01/2016
 1 |   1500 | 12/2015
 2 |   1000 | 04/2016
 2 |   1000 | 03/2016
 2 |   1000 | 02/2016
 2 |   1000 | 01/2016

结果应该是:

VisualState

我如何编写Oracle SQL,以便能够有效地产生上述结果(假设该表有数千个唯一ID)?

2 个答案:

答案 0 :(得分:2)

您可以使用connect by执行此操作,如下所示:

with sample_data as (select 1 id, 2000 income, to_date('01/02/2016', 'dd/mm/yyyy') start_date, to_date('31/05/2016', 'dd/mm/yyyy') end_date from dual union all
                     select 1 id, 1500 income, to_date('01/12/2015', 'dd/mm/yyyy') start_date, to_date('31/01/2016', 'dd/mm/yyyy') end_date from dual union all
                     select 2 id, 1000 income, to_date('01/01/2016', 'dd/mm/yyyy') start_date, to_date('30/04/2016', 'dd/mm/yyyy') end_date from dual)
select id,
       income,
       add_months(trunc(start_date, 'mm'), -1 + level) mnth
from   sample_data
connect by prior id = id
           and prior income = income
           and prior sys_guid() is not null
           and add_months(trunc(start_date, 'mm'), -1 + level) <= trunc(end_date, 'mm')
order by id, income desc, mnth desc;


        ID     INCOME MNTH     
---------- ---------- ---------
         1       2000 01-MAY-16
         1       2000 01-APR-16
         1       2000 01-MAR-16
         1       2000 01-FEB-16
         1       1500 01-JAN-16
         1       1500 01-DEC-15
         2       1000 01-APR-16
         2       1000 01-MAR-16
         2       1000 01-FEB-16
         2       1000 01-JAN-16

答案 1 :(得分:2)

如果您使用的是11gR2或更高版本,则可以使用recursive subquery factoring

with r (id, income, this_date, end_date) as (
  select id, income, trunc(start_date, 'MM'), trunc(end_date, 'MM')
  from your_table
  union all
  select id, income, this_date + interval '1' month, end_date
  from r
  where end_date > this_date
)
select id, income, to_char(this_date, 'MM/YYYY') as month
from r
order by id, this_date desc;

        ID     INCOME MONTH 
---------- ---------- -------
         1       2000 05/2016
         1       2000 04/2016
         1       2000 03/2016
         1       2000 02/2016
         1       1500 01/2016
         1       1500 12/2015
         2       1000 04/2016
         2       1000 03/2016
         2       1000 02/2016
         2       1000 01/2016

锚定成员获取起始信息 - 我可以将其截断到月初,可能是多余的,但以防万一在一个月内开始得足够晚以引起间隔添加问题。然后递归成员不断向每个现有成员添加一个月,直到它到达结束日期。