我的数据如下表所示
start_date end_date amount
15-01-2012 25-01-2012 100
26-01-2012 10-02-2012 100
11-02-2012 29-02-2012 100
我希望这些条目按月分解
2月份的金额应为
所以2月01-02-2012至29-02-2012 = 62.5 + 100 = 162.5
以便最终输出
start_date end_date amount
15-01-2012 31-01-2012 137.5
01-02-2012 29-02-2012 162.5
是否有任何方法可以在不使用PLSQL的情况下实现此目的
答案 0 :(得分:1)
您可以使用LAG函数来确定一行与上一行(已排序)之间的每日平均值。
如果您有每日平均值,则可以乘以该期间的天数。
所有在同一个sql语句中。
答案 1 :(得分:1)
我不确定你想如何计算这些值,但作为一个开始,尝试每月打破记录:
with dts as (select last_day(add_months(
to_date('20111201','yyyymmdd'),level)) ld,
add_months(
to_date('20111201','yyyymmdd'),level) sd
from dual connect by level < 12)
select case when start_date >= sd then start_date else sd end st_dt,
case when end_date <= ld then end_date else ld end en_dt, amount,
ld-sd days_in_month,
case when end_date <= ld then end_date else ld end-
case when start_date >= sd then start_date else sd end part
from t, dts
where (start_date >= sd and to_char(start_date, 'yyyymm') =
to_char(sd, 'yyyymm'))
or (end_date <= ld and to_char(end_date, 'yyyymm') =
to_char(ld, 'yyyymm'))
答案 2 :(得分:1)
我看到A.B.凯德打败了我,但这是我的解决方案:
SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'DD-MM-YYYY'
2 /
Session altered.
SQL> CREATE TABLE t (start_date DATE, end_date DATE, amount NUMBER);
Table created.
SQL> INSERT INTO t VALUES (TO_DATE('20120115','YYYYMMDD'),TO_DATE('20120125','YYYYMMDD'),100);
1 row created.
SQL> INSERT INTO t VALUES (TO_DATE('20120126','YYYYMMDD'),TO_DATE('20120210','YYYYMMDD'),100);
1 row created.
SQL> INSERT INTO t VALUES (TO_DATE('20120211','YYYYMMDD'),TO_DATE('20120229','YYYYMMDD'),100);
1 row created.
SQL>
设置了一些测试数据......
SQL> COL for_month FOR A9
SQL> COL pro_rated_start FOR A15
SQL> COL pro_rated_end FOR A13
SQL>
...并格式化了一些列......
SQL> WITH months AS (
2 SELECT TRUNC(MIN(start_date),'MM') min_start_month
3 , MONTHS_BETWEEN(TRUNC(MAX(end_date),'MM'),TRUNC(MIN(start_date),'MM')) + 1 mos
4 FROM t
5 )
6 , offset AS (
7 SELECT ROWNUM - 1 r
8 FROM (SELECT NULL
9 FROM DUAL
10 CONNECT BY LEVEL <= (SELECT mos FROM months))
11 )
12 , ranges AS (
13 SELECT ADD_MONTHS(months.min_start_month, offset.r) mo_start
14 , LAST_DAY(ADD_MONTHS(months.min_start_month, offset.r)) mo_end
15 FROM offset
16 , months
17 )
18 SELECT TO_CHAR(GREATEST(t.start_date,ranges.mo_start),'Mon YYYY') for_month
19 , MIN(GREATEST(t.start_date,ranges.mo_start)) pro_rated_start
20 , MAX(LEAST(t.end_date,ranges.mo_end)) pro_rated_end
21 , SUM(t.amount
22 * CASE
23 WHEN t.end_date < ranges.mo_end
24 AND t.start_date > ranges.mo_start
25 THEN 1
26 ELSE ((LEAST(t.end_date,ranges.mo_end)
27 - GREATEST(t.start_date,ranges.mo_start) + 1)
28 / (t.end_date - t.start_date + 1))
29 END) pro_rated_amount
30 FROM t
31 , ranges
32 WHERE t.start_date <= ranges.mo_end
33 AND t.end_date >= ranges.mo_start
34 GROUP BY TO_CHAR(GREATEST(t.start_date,ranges.mo_start),'Mon YYYY');
FOR_MONTH PRO_RATED_START PRO_RATED_END PRO_RATED_AMOUNT
--------- --------------- ------------- ----------------
Jan 2012 15-01-2012 31-01-2012 137.5
Feb 2012 01-02-2012 29-02-2012 162.5
SQL>
答案 3 :(得分:1)
SQL> select * from q10315606;
START_DATE END_DATE AMOUNT
---------- ---------- ----------
2012-01-15 2012-01-25 100
2012-01-26 2012-02-10 100
2012-02-11 2012-02-29 100
SQL> with day_generator as
2 -- this block expands out every date in the entire date range
3 (
4 select min_start_date + level - 1 as date_value
5 from (select min(start_date) as min_start_date,
6 max(end_date) - min(start_date) + 1 as total_days
7 from q10315606
8 )
9 connect by level <= total_days
10 ),
11 range_averages as
12 -- this block generates a daily average for each date range
13 (
14 select start_date, end_date,
15 end_date - start_date + 1 as days_inclusive,
16 amount / (end_date - start_date + 1) as daily_amount
17 from q10315606
18 )
19 select start_date, end_date, sum(amount) as amount
20 from (
21 -- here we cast all the dates to the minimum and maximum value found in the month
22 select min(dg.date_value)
23 over (partition by last_day(dg.date_value) ) as start_date,
24 max(dg.date_value)
25 over (partition by last_day(dg.date_value) ) as end_date,
26 ra.daily_amount as amount
27 from range_averages ra,
28 day_generator dg
29 where dg.date_value between ra.start_date and ra.end_date
30 )
31 group by start_date, end_date
32* order by start_date, end_date
amusch@AGDEV:SQL> /
START_DATE END_DATE AMOUNT
---------- ---------- ----------
2012-01-15 2012-01-31 137.5
2012-02-01 2012-02-29 162.5
答案 4 :(得分:1)
这是一次尝试:
我加入了几个月。如果一个行在两个月内将被“重复”,更确切地说将在两个月分发。
对于每行*月,我应用公式amount/(days in current row) * (days in current month)
with months as
(select add_months('1-Jan-2012', level -1) as mon
from dual
connect by level < 12)
select mon, sum(amount)
from(
select
months.mon,
amount/(end_date - start_date +1)*
(case when trunc(start_date,'MM') = months.mon
then least(last_day(start_date), end_date) - start_date +1
else end_date - greatest(months.mon, start_date) +1
end) as amount
from your_table y
join months on
(months.mon between trunc(start_date,'MM') and trunc(end_date, 'MM'))
)
group by mon;
此代码已经过测试,可以准确显示您想要的结果。