«Последние 40 месяцев» неоднозначны.
Существует несколько толкований «что последние n месяцев с даты x означают», а add_months оракула не имеет монополии на это (на самом деле большинстволюди скажут, что это не работает так, как ожидалось, просто подождите до 30.06 и спросите кого-нибудь, «какая была дата месяц назад» :))
Представьте, что сегодня 20 апреля.Включает ли «последний месяц» 15, 20, 21 или 25 марта?Это включает 02 апреля?Это зависит от того, кто-то может сказать, что «последний месяц» с 21 марта по 20 апреля.
Кто-то может сказать, что «последний месяц» с 01.03 по сегодняшний день.
Кто-то может сказать, что «последний месяц»начинается с 01.04.Кто-то может сказать, что «последний месяц» означает весь марш, но не один день апреля.
Становится еще сложнее, когда «сегодня» приближается к концу месяца, особенно в марте.
Не будьте осторожны с собой только потому, что вы не можете прочитать мысли человека, написавшего задание;)
Я написал запрос, показывающий, как разные подходы могут давать разные результаты.
CREATE OR REPLACE FUNCTION temp_can_subst_interval_months(p_date date, p_n_of_months number) RETURN NUMBER AS
V_date DATE;
BEGIN
V_Date := p_date - (NUMTOYMINTERVAL(p_n_of_months, 'month'));
RETURN 1;
EXCEPTION
WHEN OTHERS THEN
RETURN 0;
END;
with all_days as (
select to_date('2016-01-01', 'YYYY-MM-DD') + (level - 1) as d
from dual
connect by level < 1462
),
all_days_2 as (
select d date_of_query_being_run,
add_months(d, -40)as min_date_your_approach,
add_months(d, -40) + 1 as min_date_your_approach_2, -- same, but exclude the first day
trunc(add_months(d, -40), 'mm') as min_date_whole_month,
case when temp_can_subst_interval_months(d, 40) = 1 then
d - (interval '40' month)
else null
end as min_date_interval_approach
from all_days ad
order by ad.d
)
select ads.*
from all_days_2 ads
;
Наиболее интересные результаты, когда ваш подход отличается от интервального:
1 (sysdate) 2 (yours) 3 4 5 (interval)
31.01.2016 30.09.2012 01.10.2012 01.09.2012
29.02.2016 31.10.2012 01.11.2012 01.10.2012 29.10.2012
31.03.2016 30.11.2012 01.12.2012 01.11.2012
30.04.2016 31.12.2012 01.01.2013 01.12.2012 30.12.2012
29.06.2016 28.02.2013 01.03.2013 01.02.2013
30.06.2016 28.02.2013 01.03.2013 01.02.2013
31.08.2016 30.04.2013 01.05.2013 01.04.2013
30.09.2016 31.05.2013 01.06.2013 01.05.2013 30.05.2013
31.10.2016 30.06.2013 01.07.2013 01.06.2013
30.11.2016 31.07.2013 01.08.2013 01.07.2013 30.07.2013
31.01.2017 30.09.2013 01.10.2013 01.09.2013
28.02.2017 31.10.2013 01.11.2013 01.10.2013 28.10.2013
31.03.2017 30.11.2013 01.12.2013 01.11.2013
30.04.2017 31.12.2013 01.01.2014 01.12.2013 30.12.2013
29.06.2017 28.02.2014 01.03.2014 01.02.2014
30.06.2017 28.02.2014 01.03.2014 01.02.2014
31.08.2017 30.04.2014 01.05.2014 01.04.2014
30.09.2017 31.05.2014 01.06.2014 01.05.2014 30.05.2014
31.10.2017 30.06.2014 01.07.2014 01.06.2014
30.11.2017 31.07.2014 01.08.2014 01.07.2014 30.07.2014
31.01.2018 30.09.2014 01.10.2014 01.09.2014
28.02.2018 31.10.2014 01.11.2014 01.10.2014 28.10.2014
31.03.2018 30.11.2014 01.12.2014 01.11.2014
30.04.2018 31.12.2014 01.01.2015 01.12.2014 30.12.2014
29.06.2018 28.02.2015 01.03.2015 01.02.2015
30.06.2018 28.02.2015 01.03.2015 01.02.2015
31.08.2018 30.04.2015 01.05.2015 01.04.2015
30.09.2018 31.05.2015 01.06.2015 01.05.2015 30.05.2015
31.10.2018 30.06.2015 01.07.2015 01.06.2015
30.11.2018 31.07.2015 01.08.2015 01.07.2015 30.07.2015
31.01.2019 30.09.2015 01.10.2015 01.09.2015
28.02.2019 31.10.2015 01.11.2015 01.10.2015 28.10.2015
31.03.2019 30.11.2015 01.12.2015 01.11.2015
30.04.2019 31.12.2015 01.01.2016 01.12.2015 30.12.2015
30.06.2019 29.02.2016 01.03.2016 01.02.2016
31.08.2019 30.04.2016 01.05.2016 01.04.2016
30.09.2019 31.05.2016 01.06.2016 01.05.2016 30.05.2016
31.10.2019 30.06.2016 01.07.2016 01.06.2016
30.11.2019 31.07.2016 01.08.2016 01.07.2016 30.07.2016
Примечание:
Возможно, таблица содержит что-то вроде «ожидаемых будущих продаж», и они хотят, чтобы выотфильтровать даты позже sysdate;)?