split from date and To date in multiple months using oracle sql - sql

In need to split lines with From date and To date in multiple months.
I want to split like this.Target
Sample 1
10/02/2023 - 28/02/2023
Target
10/02/2023 - 28/02/2023
Sample 2
10/02/2023 - 29/08/2023
Target
10/02/2023 - 28/02/2023
01/03/2023 - 31/03/2023
01/04/2023 - 29/08/2023
Sample 3
01/04/2022 - 31/03/2023
Target
01/04/2022 - 28/02/2023
01/03/2023 - 31/03/2023
I succeed in first steps but I'm now stucked
For the moment I can only do like this[Existing]
But in yellow wrong values,
Here below my code
CASE WHEN qd.valid_from >= TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')
THEN
TRUNC(qd.valid_from)
ELSE
TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')
END new_start_date,
CASE WHEN last_day(TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')) >= last_day(TRUNC(add_months(qd.valid_from,2),'MM'))
THEN
TRUNC(qd.valid_to)
ELSE
TRUNC(last_day(TRUNC(add_months(qd.valid_from,COLUMN_VALUE - 1),'MM')))
END new_end_date
FROM QUOTATIONS_UO QH
),
TABLE(
CAST(
MULTISET
(
SELECT LEVEL
FROM dual
CONNECT BY add_months(TRUNC(qd.valid_from,'MM'),LEVEL - 1) <= add_months(TRUNC(qd.valid_from,'MM'),2)
) AS sys.OdciNumberList
)
)
)

It is unclear what is it about months february and march vs all the others, but if you want to split dates by months then maybe this could help you:
Select DISTINCT
ID,
LEVEL "LVL",
CASE WHEN LEVEL = 1 THEN FROM_DATE END "FROM_DATE",
CASE WHEN LEVEL = 1 THEN UNTIL_DATE END "UNTIL_DATE",
CASE WHEN MONTH_UNTIL = MONTH_FROM THEN FROM_DATE
WHEN LEVEL = 1 THEN FROM_DATE
WHEN MONTHS > 1 And LEVEL < MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 2)) + 1
WHEN MONTHS > 1 And LEVEL = MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 2)) + 1
WHEN MONTHS > 0 And MONTHS < LEVEL THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 2)) + 1
ELSE UNTIL_DATE
END "FROM_DATE_2",
--
CASE WHEN MONTH_UNTIL = MONTH_FROM THEN UNTIL_DATE
--WHEN LEVEL = 1 THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 1))
WHEN MONTHS > 1 And LEVEL < MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 1))
WHEN MONTHS > 1 And LEVEL = MONTHS THEN LAST_DAY(ADD_MONTHS(FROM_DATE, LEVEL - 1))
ELSE UNTIL_DATE
END "UNTIL_DATE_2"
FROM
(
Select
ID, FROM_DATE, UNTIL_DATE,
To_Char(FROM_DATE, 'yyyymm') "MONTH_FROM",
To_Char(UNTIL_DATE, 'yyyymm') "MONTH_UNTIL",
FLOOR(MONTHS_BETWEEN(UNTIL_DATE, FROM_DATE)) "MONTHS"
From
tbl
)
CONNECT BY LEVEL < MONTHS + 2
ORDER BY ID, LVL
... which with sample data like here:
WITH
tbl (ID, FROM_DATE, UNTIL_DATE) AS
(
Select 1, To_Date('10.02.2023', 'dd.mm.yyyy'), To_Date('28.02.2023', 'dd.mm.yyyy') From Dual Union All
Select 2, To_Date('10.02.2023', 'dd.mm.yyyy'), To_Date('29.08.2023', 'dd.mm.yyyy') From Dual Union All
Select 3, To_Date('01.04.2022', 'dd.mm.yyyy'), To_Date('31.03.2023', 'dd.mm.yyyy') From Dual
)
... results as:
ID LVL FROM_DATE UNTIL_DATE FROM_DATE_2 UNTIL_DATE_2
---------- ---------- --------- ---------- ----------- ------------
1 1 10-FEB-23 28-FEB-23 10-FEB-23 28-FEB-23
2 1 10-FEB-23 29-AUG-23 10-FEB-23 28-FEB-23
2 2 01-MAR-23 31-MAR-23
2 3 01-APR-23 30-APR-23
2 4 01-MAY-23 31-MAY-23
2 5 01-JUN-23 30-JUN-23
2 6 01-JUL-23 31-JUL-23
2 7 01-AUG-23 29-AUG-23
3 1 01-APR-22 31-MAR-23 01-APR-22 30-APR-22
3 2 01-MAY-22 31-MAY-22
3 3 01-JUN-22 30-JUN-22
3 4 01-JUL-22 31-JUL-22
3 5 01-AUG-22 31-AUG-22
3 6 01-SEP-22 30-SEP-22
3 7 01-OCT-22 31-OCT-22
3 8 01-NOV-22 30-NOV-22
3 9 01-DEC-22 31-DEC-22
3 10 01-JAN-23 31-JAN-23
3 11 01-FEB-23 28-FEB-23
3 12 01-MAR-23 31-MAR-23

Related

oracle sql query months

I'm fairly new to SQL and I have a question regarding a query.
I would like to use a "with-clause" to create a temporary table that displays all months between two dates.
I will then use this temporary table to apply a filter to my actual table.
My query:
WITH monlist(mon, next_mon) as (
select add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level - 1), add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level)
from dual
connect by level <= (months_between(to_date(:P6_DATUM_BIS,'DD-MM-YYYY'), to_date(:P6_DATUM_VON,'DD-MM-YYYY')))
The problem is that I want to narrow it down to days, i.e. if I want to start from 05-01-2022 (DD-MM-YYY), this is not possible.
The temporary table starts with the beginning of the month (01-01-2022).
It is similar with the end - it is rounded up to the full month.
Is there a way to change the query so that the initial and final values are accepted correctly?
I would like to get the following output:
mon next_mon
05-01.2022 - 01-02-2022
01-02-2022 - 28-02-2022
...
01-10-2022 - 15-10-2022 (If end-date is 15-10-2022)
If it were PL/SQL, you'd use IF-THEN-ELSE; in SQL, use CASE expression. Something like this (example ran in SQL*Plus, hence substitution variables):
SQL> alter session set nls_date_format = 'dd-mm-yyyy';
Session altered.
SQL> set ver off
SQL>
SQL> WITH monlist as
2 (select add_months(trunc(to_date('&&P6_DATUM_VON','DD-MM-YYYY'), 'MM'), level - 1) mon,
3 add_months(trunc(to_date('&&P6_DATUM_VON','DD-MM-YYYY'), 'MM'), level) next_mon,
4 level lvl
5 from dual
6 connect by level <= months_between(to_date('&&P6_DATUM_BIS','DD-MM-YYYY'),
7 to_date('&&P6_DATUM_VON','DD-MM-YYYY')
8 ) + 1
9 )
10 select case when lvl = 1
11 then to_date('&&P6_DATUM_VON','DD-MM-YYYY') else mon end mon,
12 case when lvl = (select max(lvl) from monlist)
13 then to_date('&&P6_DATUM_BIS','DD-MM-YYYY') else next_mon end next_mon
14 from monlist
15 order by lvl;
Enter value for p6_datum_von: 05-01-2022
Enter value for p6_datum_bis: 15-10-2022
MON NEXT_MON
---------- ----------
05-01-2022 01-02-2022
01-02-2022 01-03-2022
01-03-2022 01-04-2022
01-04-2022 01-05-2022
01-05-2022 01-06-2022
01-06-2022 01-07-2022
01-07-2022 01-08-2022
01-08-2022 01-09-2022
01-09-2022 01-10-2022
01-10-2022 15-10-2022
10 rows selected.
SQL>
In Apex (you do use it, right? Regarding :P6_... item names?), that would be just
WITH monlist as
(select add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level - 1) mon,
add_months(trunc(to_date(:P6_DATUM_VON,'DD-MM-YYYY'), 'MM'), level) next_mon,
level lvl
from dual
connect by level <= months_between(to_date(:P6_DATUM_BIS,'DD-MM-YYYY'),
to_date(:P6_DATUM_VON,'DD-MM-YYYY')
) + 1
)
select case when lvl = 1
then to_date(:P6_DATUM_VON,'DD-MM-YYYY') else mon end mon,
case when lvl = (select max(lvl) from monlist)
then to_date(:P6_DATUM_BIS,'DD-MM-YYYY') else next_mon end next_mon
from monlist
order by lvl;

Generating sequence skipping by 2 Oracle

I have the below query.But I want to tweak the output to skip 2 consecutive numbers on every cycle.
For example skip 1,2 in 2nd cycle . Skip 3,4 in 3rd cycle . Skip 5,6 in 4th cycle and so on.
Also, there will be 2 input variables (i) the number to be removed/added (ii) from which date.
Once this is passed the sequence will have to be recalculate from that date on wards.
I am using Oracle version 12.1
SELECT TRUNC(sysdate, 'Y') + level - 1 AS "date", MOD(level - 1, 10) + 1 AS col1
FROM dual
CONNECT BY level <= ADD_MONTHS(TRUNC(sysdate, 'Y'), 12) - TRUNC(sysdate, 'Y')
Date Col1 Expected Output
1/1/2022 1 1
1/2/2022 2 2
1/3/2022 3 3
1/4/2022 4 4
1/5/2022 5 5
1/6/2022 6 6
1/7/2022 7 7
1/8/2022 8 8
1/9/2022 9 9
1/10/2022 10 10
1/11/2022 1 3
1/12/2022 2 4
1/13/2022 3 5
1/14/2022 4 6
1/15/2022 5 7
1/16/2022 6 8
1/17/2022 7 9
1/18/2022 8 10
1/19/2022 9 1
1/20/2022 10 2
1/21/2022 1 5
1/22/2022 2 6
1/23/2022 3 7
1/24/2022 4 8
1/25/2022 5 9
1/26/2022 6 10
1/27/2022 7 1
1/28/2022 8 2
1/29/2022 9 3
1/30/2022 10 4
1/31/2022 1 7
2/1/2022 2 8
2/2/2022 3 9
2/3/2022 4 10
You can use some more arithmetical functions such as FLOOR() and CEIL() along with precomputing unmatched values within a subquery, and then filter out by the incremented values upto the currently existing expression's value of
ADD_MONTHS(TRUNC(sysdate, 'Y'), 12) - TRUNC(sysdate, 'Y')
such as
WITH d AS
(
SELECT SUM(CASE
WHEN MOD(FLOOR((level-.1)/10),6) = CEIL((MOD(level - 1, 10) + 1)/2)
THEN
0
ELSE
1
END)
OVER (ORDER BY level) AS rn,
ADD_MONTHS(TRUNC(sysdate, 'Y'), 12) - TRUNC(sysdate, 'Y') AS day_diff,
MOD(level - 1, 10) + 1 AS col1,
MOD(FLOOR((level-.1)/10),6) AS col2,
CEIL((MOD(level - 1, 10) + 1)/2) AS col3
FROM dual
CONNECT BY level <= (ADD_MONTHS(TRUNC(sysdate, 'Y'), 12) - TRUNC(sysdate, 'Y'))*2
)
SELECT TRUNC(sysdate, 'Y') + rn - 1 AS "date", col1
FROM d
WHERE col2 != col3
AND rn <= day_diff
ORDER BY rn
Demo
Wrote below . Thanks for your answer as well. I just made some columns in excel and wrote some functions to get it
WITH Y AS
(SELECT TRUNC(SYSDATE, 'Y') + LEVEL - 1 dt,
MOD(LEVEL - 1, 10) + 1 AS grpid,
LEVEL rnum
FROM dual
CONNECT BY LEVEL <=
ADD_MONTHS(TRUNC(SYSDATE, 'Y'), 12) - TRUNC(SYSDATE, 'Y')),
Z AS
(SELECT dt,
rnum,
COUNT(CASE
WHEN grpid = 1 THEN
1
END) OVER(ORDER BY dt) - 1 as grp
FROM y)
SELECT z.*,
REGEXP_REPLACE(CASE
WHEN MOD(rnum, grp * 10) = 1 THEN
MOD(grp + grp + 1, 10)
WHEN MOD(rnum, grp * 10) = 2 THEN
MOD(grp + grp + 2, 10)
ELSE
MOD(rnum - grp * (10 - 2), 10)
END,
'^0$',
10) output
FROM Z;

Calculate manual week number of year in Oracle SQL

i have a date column and along that i need to calculate another column in oracle for week number of they year, the weeks should be from sunday to saturday, starting first day of the year.
for example for current year
Week 1 : 1 Jan 2020 (Wednesday) - 4 Jan 2020(Saturday)
Week 2 : 5 Jan 2020 (Sunday) - 11 Jan 2020(Saturday)
. . . . .
Week 5 : 26 Jan 2020 (Sunday) - 1 Feb 2020 (Saturday)
and so on...
You need to write your own logic using a hierarchy query.
Something like the following:
SQL> SELECT WEEKNUMBER,
2 WEEK_START,
3 CASE WHEN WEEKNUMBER = 1 THEN FIRST_WEEKEND ELSE WEEK_START + 6 END AS WEEK_END
4 FROM
5 (SELECT
6 CASE
7 WHEN LEVEL = 1 THEN FIRST_DAY
8 ELSE FIRST_WEEKEND + ( LEVEL - 2 ) * 7 + 1
9 END AS WEEK_START,
10 FIRST_WEEKEND,
11 LEVEL AS WEEKNUMBER
12 FROM
13 ( SELECT
14 TRUNC(SYSDATE, 'YEAR') FIRST_DAY,
15 NEXT_DAY(TRUNC(SYSDATE, 'YEAR'), 'SATURDAY') FIRST_WEEKEND
16 FROM DUAL )
17 CONNECT BY
18 CASE WHEN LEVEL = 1 THEN FIRST_DAY
19 ELSE FIRST_WEEKEND + ( LEVEL - 2 ) * 7 + 1
20 END < ADD_MONTHS(TRUNC(SYSDATE, 'YEAR'), 12));
WEEKNUMBER WEEK_STAR WEEK_END
---------- --------- ---------
1 01-JAN-20 04-JAN-20
2 05-JAN-20 11-JAN-20
3 12-JAN-20 18-JAN-20
4 19-JAN-20 25-JAN-20
5 26-JAN-20 01-FEB-20
6 02-FEB-20 08-FEB-20
7 09-FEB-20 15-FEB-20
8 16-FEB-20 22-FEB-20
9 23-FEB-20 29-FEB-20
10 01-MAR-20 07-MAR-20
11 08-MAR-20 14-MAR-20
.......
.......
53 27-DEC-20 02-JAN-21
Cheers!!
One other option would be
with t as
(
select trunc(sysdate,'yyyy')+level-1 as day, to_char(trunc(sysdate,'yyyy')+level-1,'DY','NLS_DATE_LANGUAGE=AMERICAN') as weekday, level - 1 as lvl
from dual
connect by level <= 366
), t1 as
(
select case
when lvl = 0 then
day
else
case
when weekday = 'SUN' then
day
end
end as day1,
lvl
from t
), t2 as
(
select case
when weekday = 'SAT' then
day
end as day2,
lvl
from t
)
select concat( 'Week ', wk1) as week, day1, day2
from
(
select row_number() over (order by lvl) wk1, day1
from t1 where day1 is not null ) t1
left join
(
select row_number() over (order by lvl) wk2, day2
from t2 where day2 is not null ) t2
on wk2 = wk1
by using select .. from dual connect by level syntax and case..when expression to scan all the current year.
Demo

How to get all days in month? [duplicate]

This question already has answers here:
How to populate calendar table in Oracle?
(3 answers)
Closed 8 years ago.
Possible to get all days in month in Oracle SQL/PLSQL as table ?
select * from bla-bla-bla DUAL
results:
1 rec: 01.01.2012
2 rec: 02.01.2012
3 rec: 03.01.2012
...
4 rec: 31.01.2012
?
this is what you are looking for;
select to_date('01.01.2012','dd.mm.yyyy')+level-1
from dual
connect by level <= TO_CHAR(LAST_DAY(to_date('01.01.2012','dd.mm.yyyy')),'DD')
ADD_MONTHS (dt, 1) - dt is also an alternative.
For a particular month of an year, you need to hardcode the date :
WITH d AS
(SELECT TRUNC ( to_date('01.01.2012','dd.mm.yyyy'), 'MM' ) - 1 AS dt
FROM dual
)
SELECT dt + LEVEL
FROM d
CONNECT BY LEVEL <= ADD_MONTHS (dt, 1) - dt
/
Else, to get the list for current month, simply use SYSDATE instead of hardcoding the date :
SQL> WITH d AS
2 (SELECT TRUNC(sysdate,'MM') -1 AS dt FROM dual
3 )
4 SELECT dt + LEVEL
5 FROM d
6 CONNECT BY LEVEL <= ADD_MONTHS (dt, 1) - dt
7 /
DT+LEVEL
---------
01-OCT-14
02-OCT-14
03-OCT-14
04-OCT-14
05-OCT-14
06-OCT-14
07-OCT-14
08-OCT-14
09-OCT-14
10-OCT-14
11-OCT-14
12-OCT-14
13-OCT-14
14-OCT-14
15-OCT-14
16-OCT-14
17-OCT-14
18-OCT-14
19-OCT-14
20-OCT-14
21-OCT-14
22-OCT-14
23-OCT-14
24-OCT-14
25-OCT-14
26-OCT-14
27-OCT-14
28-OCT-14
29-OCT-14
30-OCT-14
31-OCT-14
31 rows selected.
SQL>

Oracle : break down multiple entries monthwise

i have data in table as below
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
i want these entries to be break down monthwise as below
15-01 to 25-01 = 100
26-01 to 31-01 = 100/((10-02-2012 - 26-01-2012) +1 ) * ((31-01-2012 - 26-01-2012) + 1) = 37.5
so for period of 15-01-2012 to 31-01-2012 = 100 + 37.5 = 137.5
for month of february amount should be
01-02 to 10-02 = 100/((10-02-2012 - 26-01-2012) +1 ) * ((01-02-2012 - 10-02-2012) + 1) = 62.5
11-02 to 29-02 = 100
so for the february 01-02-2012 to 29-02-2012 = 62.5 + 100 = 162.5
so that final output should be
start_date end_date amount
15-01-2012 31-01-2012 137.5
01-02-2012 29-02-2012 162.5
is there any method to achieve this without using PLSQL
you can use a LAG function to determine the daily average between one row and a previous (sorted) row.
once you have a daily average, you can multiply by the number of days in the period.
all in the same sql statement.
I'm not sure how you want to calculate the values, but as a start, try to break the records monthly:
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'))
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
This is a try:
I had a join with months. If a row is on two months will be "duplicated", more precisely will by distributed on both months.
For every row*month I apply the formula 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;
This code was tested and gives exactly your desired results.
I see A.B. Cade beat me to it, but here's my solution:
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>
Having set up some test data...
SQL> COL for_month FOR A9
SQL> COL pro_rated_start FOR A15
SQL> COL pro_rated_end FOR A13
SQL>
... and formatted some columns ...
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>