我遇到了一个无法解决的问题。我有A和B钱,我可以在规定的时间内花钱。这些是DB中的以下两行(包含begin_date,end_date和amount列):
所以这些日期重叠,这意味着我可以在2017.07.01之间花更多的钱。和2015.09.30。所以在输出中我必须得到以下内容:
考虑到我每个月平均花钱,我如何选择这些范围并计算金额?如果我可以定义3个日期范围,我想我可以计算金额,但日期真的很棘手,我无法处理它们。
我使用的是Oracle 11g。
答案 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
最后排除最后的人工开放期间,加上任何总数为零的情况(如果存在任何间隙(小样本中没有,但可能出现在更大的数据集中) ;并将新月度金额乘以新时期的月数。