Reputation: 65732
Oracle has a last_day()
function:
SELECT LAST_DAY(to_date('01/01/2016','DD/MM/YYYY')) from dual;
Results:
31/01/2016
How can I get a list of the EndOfMonths in a Date Range to use in a WHERE Clause, currently I'm using a big string and it is not intuitive or future proof eg:
SELECT * FROM Balances
WHERE TheDate IN
('31/Jan/2016','29/Feb/2016', '31/Mar/2016','30/Apr/2016', '31/May/2016','30/Jun/2016', '31/Jul/2016','31/Aug/2016',
'30/Sep/2016', '31/Oct/2016','30/Nov/2016')
I'd prefer to use a function to plug in Start and End Dates.
Upvotes: 1
Views: 8325
Reputation: 12179
Try something like this to generate a last day of month range:
SELECT LAST_DAY(add_months(to_date('01/01/2016','DD/MM/YYYY'), level) )
from dual
CONNECT BY LEVEL <= 10
Change 10 to # months you need. This assumes "TheDate" is a proper oracle DATE type. Wrap with to_char if needed to format as string.
With @JeremyThompsons Months_Between suggestion:
SELECT LAST_DAY(add_months(to_date('01-01-1991','DD/MM/YYYY'), level) )
from dual
CONNECT BY LEVEL <=
(SELECT MONTHS_BETWEEN
(TO_DATE('02-02-1999','MM-DD-YYYY'),
TO_DATE('01-01-1991','MM-DD-YYYY') ) "Months"
FROM dual);
The final query with @mathguys function order suggestion:
SELECT * FROM Balances b
WHERE TheDate IN
(SELECT add_months(LAST_DAY(to_date('28/Feb/2015','DD-MM-YYYY')), level)
from dual
CONNECT BY LEVEL <=
(SELECT MONTHS_BETWEEN
(TO_DATE('30/Nov/2016','DD-MM-YYYY'),
TO_DATE('28/Feb/2015','DD-MM-YYYY') ) "Months"
FROM dual));
And one more of @mathguys optimizations, no need for scalar subquery:
SELECT * FROM Balances b
WHERE TheDate IN
(SELECT add_months(LAST_DAY(to_date('28/Feb/2015','DD-MM-YYYY')),level)
from dual
CONNECT BY LEVEL <= MONTHS_BETWEEN
(TO_DATE('30/Nov/2016','DD-MM-YYYY'),
TO_DATE('28/Feb/2015','DD-MM-YYYY')) );
Upvotes: 1
Reputation: 2453
You can create a function like the following which will return the end of months for all the months:
create or replace function getEndOfMonths return varchar2 as
cnt number;
current_year varchar2(5);
end_of_months varchar2(180) := '';
end_of_month varchar2(13);
begin
select to_char(sysdate,'YYYY') into current_year from dual;
for cnt in 1..12 loop
SELECT LAST_DAY(to_date('01/'||cnt||'/'||current_year,'DD/MM/YYYY')) into end_of_month from dual;
end_of_months := end_of_months||','||end_of_month;
end loop;
return substr(end_of_months,2);
end;
/
Update: Following is based on month range:
create or replace function getEndOfMonths(start_month number, end_month number) return varchar2 as
cnt number;
current_year varchar2(5);
end_of_months varchar2(180) := '';
end_of_month varchar2(13);
begin
select to_char(sysdate,'YYYY') into current_year from dual;
for cnt in start_month..end_month loop
SELECT LAST_DAY(to_date('01/'||cnt||'/'||current_year,'DD/MM/YYYY')) into end_of_month from dual;
end_of_months := end_of_months||','||end_of_month;
end loop;
return substr(end_of_months,2);
end;
/
Upvotes: 0