SELECT
a.dt_base,
a.dt,
a.months,
a.days,
a.mms,
a.my_months,
a.bias,
a.day_part,
a.my_add_months
FROM
(
SELECT
a.dt_base,
a.dt,
a.months,
a.days,
a.mms,
a.my_months,
31 - TO_NUMBER(TO_CHAR(LAST_DAY(ADD_MONTHS(a.dt_base,TRUNC(a.months))),'dd')) bias,
((a.months - TRUNC(a.months)) * 31) day_part,
CASE WHEN TO_CHAR(ADD_MONTHS(a.dt_base,TRUNC(a.months)),'yyyymm') != TO_CHAR((ADD_MONTHS(a.dt_base,TRUNC(a.months)) + ((a.months - TRUNC(a.months)) * 31)),'yyyymm') THEN
ADD_MONTHS(a.dt_base,TRUNC(a.months)) + ((a.months - TRUNC(a.months)) * 31) - (31 - TO_NUMBER(TO_CHAR(LAST_DAY(ADD_MONTHS(a.dt_base,TRUNC(a.months))),'dd')))
ELSE
ADD_MONTHS(a.dt_base,TRUNC(a.months)) + ((a.months - TRUNC(a.months)) * 31)
END my_add_months
FROM
(
SELECT
a.dt_base,
a.dt,
a.months,
a.days,
a.mms,
mms + days / 31 my_months
FROM
(
SELECT
a.dt_base,
a.dt,
a.months,
CASE WHEN TO_CHAR(a.dt_base,'dd') > to_char(a.dt,'dd') THEN
31 - TO_NUMBER(TO_CHAR(a.dt_base,'dd')) + TO_NUMBER(TO_CHAR(a.dt,'dd'))
ELSE
TO_NUMBER(TO_CHAR(a.dt,'dd')) - TO_NUMBER(TO_CHAR(a.dt_base,'dd'))
END days
, CASE WHEN TO_CHAR(a.dt_base,'dd') > TO_CHAR(a.dt,'dd') THEN
( TO_NUMBER(TO_CHAR(a.dt,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt,'mm')) )
-
( TO_NUMBER(TO_CHAR(a.dt_base,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt_base,'mm')) )
- 1
ELSE
( TO_NUMBER(TO_CHAR(a.dt,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt,'mm')) )
-
( TO_NUMBER(TO_CHAR(a.dt_base,'yyyy')) * 12 + TO_NUMBER(TO_CHAR(a.dt_base,'mm')) )
END mms
FROM
(
SELECT
dt_base,
dt,
MONTHS_BETWEEN(dt,dt_base) months
FROM
(
SELECT
TRUNC(sysdate,'dd') dt_base,
TRUNC(sysdate,'dd') + level - 1 dt
FROM dual
CONNECT BY level < 36500
) a
) a
)a
) a
) a
WHERE a.dt != a.my_add_months