Sql Oracle:每月分解多个条目
我的数据如下表所示Sql Oracle:每月分解多个条目,sql,oracle,date-arithmetic,Sql,Oracle,Date Arithmetic,我的数据如下表所示 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 我想把这些条目分解如下 start_date end_date amount 15-01-2012 25-01-2012 100 26-01
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
我想把这些条目分解如下
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
15-01至25-01=100
26-01至31-01=100/10-02-2012-26-01-2012+1*31-01-2012-26-01-2012+1=37.5
因此,在2012年1月15日至2012年1月31日期间,平均值为100+37.5=137.5
2月份的金额应为
start_date end_date amount
15-01-2012 31-01-2012 137.5
01-02-2012 29-02-2012 162.5
01-02至10-02=100/10-02-2012-26-01-2012+1*01-02-2012-10-02-2012+1=62.5
11-02至29-02=100
因此,对于2012年2月1日至2012年2月29日的数据,其=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的情况下实现这一点?您可以使用滞后函数来确定一行和上一个排序行之间的每日平均值 一旦你有了一个每日平均数,你就可以乘以这个时期的天数
都在同一个sql语句中。您可以使用滞后函数来确定一行和上一个排序行之间的每日平均值 一旦你有了一个每日平均数,你就可以乘以这个时期的天数
都在同一个sql语句中。我不确定您希望如何计算这些值,但首先,请尝试每月打破记录:
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'))
我不确定您希望如何计算这些值,但首先,请尝试每月打破记录:
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'))
我看到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>
我看到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>
这是一次尝试:
我和几个月前有过一次聚会。如果一行在两个月内将被复制,更准确地说,将在两个月内分发。
对于每行*月,我应用公式“当前行的金额/天数*当前月的天数”
这段代码经过测试,给出了您想要的结果。这是一次尝试:
我和几个月前有过一次聚会。如果一行在两个月内将被复制,更准确地说,将在两个月内分发。
对于每行*月,我应用公式“当前行的金额/天数*当前月的天数”
此代码经过测试,并给出了您想要的结果。抱歉-我看不出您从哪里获得62.5这样的值?请使用伪代码,而不是直接获得值,进行更好的解释。加上二月份的微积分。对不起,我看不出你从哪里得到像62.5这样的值?请更好地解释,使用伪代码,而不是直接得到值。加上2月份的演算。