将2个db行拆分为3个日期范围

时间:2015-06-03 13:25:03

标签: oracle

我遇到了一个无法解决的问题。我有A和B钱,我可以在规定的时间内花钱。这些是DB中的以下两行(包含begin_date,end_date和amount列):

  • A:2015.01.01.-2015.09.30。 10.000 $
  • B:2015.07.01.-2015.12.31。 7.000 $

所以这些日期重叠,这意味着我可以在2017.07.01之间花更多的钱。和2015.09.30。所以在输出中我必须得到以下内容:

  • 2015.01.01.-2015年7月1日。 X $
  • 2015.07.01.-2015年9月30日。 Y $
  • 2015.09.30.-2015年12月31日。 Z $

考虑到我每个月平均花钱,我如何选择这些范围并计算金额?如果我可以定义3个日期范围,我想我可以计算金额,但日期真的很棘手,我无法处理它们。

我使用的是Oracle 11g。

1 个答案:

答案 0 :(得分:0)

this approach大量借用,更详细地解释了here以及一些替代方案,以获取您可以执行的日期范围:

with cte1 as
(
  select begin_date as marker_date, 1 as type
  from your_table
  union all
  select end_date + 1 as marker_date, -1 as type
  from your_table
),
cte2 as (
  select marker_date as begin_date,
    lead(marker_date) over (order by marker_date) - 1 as end_date,
    sum(type) over (order by marker_date) as periods
  from cte1
)
select begin_date, end_date from cte2
where end_date is not null and periods > 0;

这给了你:

BEGIN_DATE END_DATE 
---------- ----------
2015-01-01 2015-06-30
2015-07-01 2015-09-30
2015-10-01 2015-12-31

我假设您实际上并不希望生成的时段重叠一天,而是希望它们像原来的两行一样是月份的开头和结尾。

要获得金额 - 如果我已经理解了您所描述的内容 - 您可以修改该金额以包括每个日期的金额变化,无论是正数还是负数,取决于它是一个期间的开始还是结束:

with cte1 as
(
  select begin_date as marker_date,
    amount / months_between(end_date + 1, begin_date) as monthly_amount
  from your_table
  union all
  select end_date + 1 as marker_date,
    -amount / months_between(end_date + 1, begin_date) as monthly_amount
  from your_table
),
cte2 as (
  select marker_date as begin_date,
    lead(marker_date) over (order by marker_date) - 1 as end_date,
    sum(monthly_amount) over (order by marker_date) as total_monthly_amount
  from cte1
)
select begin_date, end_date,
  total_monthly_amount * months_between(end_date + 1, begin_date) as amount
from cte2
where end_date is not null and total_monthly_amount > 0;

BEGIN_DATE END_DATE       AMOUNT
---------- ---------- ----------
2015-01-01 2015-06-30 6.66666667
2015-07-01 2015-09-30 6.83333333
2015-10-01 2015-12-31        3.5

这是通过将原始期间的金额除以其涵盖的月数来实现的:

select begin_date as marker_date, amount,
  months_between(end_date + 1, begin_date) as months,
  amount / months_between(end_date + 1, begin_date) as monthly_amount
from your_table
union all
select end_date + 1 as marker_date, amount,
  months_between(end_date + 1, begin_date) as months,
  -amount / months_between(end_date + 1, begin_date) as monthly_amount
from your_table;

MARKER_DATE     AMOUNT     MONTHS MONTHLY_AMOUNT
----------- ---------- ---------- --------------
2015-01-01          10          9     1.11111111
2015-07-01           7          6     1.16666667
2015-10-01          10          9    -1.11111111
2016-01-01           7          6    -1.16666667

然后将其用作CTE并应用引导分析函数来重建新的非重叠时段:

with cte1 as
(
  select begin_date as marker_date,
    months_between(end_date + 1, begin_date) as months,
    amount / months_between(end_date + 1, begin_date) as monthly_amount
  from your_table
  union all
  select end_date + 1 as marker_date,
    months_between(end_date + 1, begin_date) as months,
    -amount / months_between(end_date + 1, begin_date) as monthly_amount
  from your_table
)
select marker_date as begin_date,
  lead(marker_date) over (order by marker_date) - 1 as end_date,
  sum(monthly_amount) over (order by marker_date) as total_monthly_amount,
  months_between(lead(marker_date) over (order by marker_date), marker_date) as months
from cte1;

BEGIN_DATE END_DATE   TOTAL_MONTHLY_AMOUNT     MONTHS
---------- ---------- -------------------- ----------
2015-01-01 2015-06-30           1.11111111          6
2015-07-01 2015-09-30           2.27777778          3
2015-10-01 2015-12-31           1.16666667          3
2016-01-01                      0.00000000           

最后排除最后的人工开放期间,加上任何总数为零的情况(如果存在任何间隙(小样本中没有,但可能出现在更大的数据集中) ;并将新月度金额乘以新时期的月数。