I think this does what you've described:
select to_char(monthly, 'YYYY-MM-DD') as mdate,
to_char(daily, 'YYYY-MM-DD') as ddate
from (
select distinct monthly,
max(case when daily = trunc(sysdate) then daily end)
over (partition by monthly) as daily,
dense_rank() over (order by monthly desc) as rn
from z_dates
where daily <= trunc(sysdate)
)
where rn <= 3
order by monthly;
The inner select gets today's date for the current pseudo-month and null otherwise, and assigns a rank to each month. The outer select then limits that to three rows. If you only wanted the value for two months ago (which is slightly unclear) then just make that = 3
instead of <= 3
. The filter where daily <= trunc(sysdate)
is in case there are any future dates, which is plausible from how you've described the table, but doesn't do any harm anyway.
If you do only want the two-months-prior date then it's even simpler, you don't need to do the max()
part or get ddate
:
select to_char(monthly, 'YYYY-MM-DD') as mdate
from (
select distinct monthly,
dense_rank() over (order by monthly desc) as rn
from z_dates
where daily <= trunc(sysdate)
)
where rn = 3;