我有一个带有收入和开始/结束日期的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)?
答案 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
锚定成员获取起始信息 - 我可以将其截断到月初,可能是多余的,但以防万一在一个月内开始得足够晚以引起间隔添加问题。然后递归成员不断向每个现有成员添加一个月,直到它到达结束日期。