AM_86
AM_86

Reputation: 115

Get COUNT of DISTINCT Months Between Two Dates

I am trying to get count of distinct months between two dates. However, I am getting a missing right parenthesis error. As with many of us I like using dual table on the fly.

Here is the query. Can you please advise what I am doing wrong?

SELECT 
COUNT(DISTINCT(TRUNC BETWEEN TO_DATE('2019-08-01','YYYY-MM-DD') AND TO_DATE('2020-07-07','YYYY-MM-DD'),'MM'))
FROM dual

Upvotes: 0

Views: 648

Answers (3)

LNM
LNM

Reputation: 1

months_between may not be solution for all scenarios; example:

SELECT MONTHS_BETWEEN (TO_DATE('2021-12-20','YYYY-MM-DD'),TO_DATE('2022-01-05','YYYY-MM-DD')) FROM dual will result is 0.5 months; but actually both dec and jan are used in query and expected result may 2.

So using above example of with function will provide correct result no matter.

Upvotes: 0

Alex Poole
Alex Poole

Reputation: 191275

Counting isn't the right tool for this really; your trunc() is missing its opening parenthesis, but BETWEEN is a condition not a function, so that is also wrong.

Oracle has the months_between() function to do this; it will give a fractional value, so you can use floor() to get the number of complete months, or ceil() to get the number of partial months:

select
  months_between (date '2020-07-07', date '2019-08-01') as result1,
  floor(months_between (date '2020-07-07', date '2019-08-01')) as result2,
  ceil(months_between (date '2020-07-07', date '2019-08-01')) as result3
from dual;

   RESULT1    RESULT2    RESULT3
---------- ---------- ----------
11.1935484         11         12

If you wanted to list the months then you could use a hierarchcal query or recursive subquery factoring, e.g.:

with rcte (this_month, last_month) as (
  select trunc(date '2019-08-01', 'MM'), trunc(date '2020-07-07', 'MM')
  from dual
  union all
  select r.this_month + interval '1' month, r.last_month
  from rcte r
  where r.this_month < r.last_month
)
select this_month
from rcte
order by this_month;

THIS_MONTH
----------
2019-08-01
2019-09-01
2019-10-01
...
2020-06-01
2020-07-01

and count those instead:

with rcte (this_month, last_month) as (
  select trunc(date '2019-08-01', 'MM'), trunc(date '2020-07-07', 'MM')
  from dual
  union all
  select r.this_month + interval '1' month, r.last_month
  from rcte r
  where r.this_month < r.last_month
)
select count(this_month) as result
from rcte;

RESULT
------
    12

but that's more work than you need to do if you only want that number.

db<>fiddle

Upvotes: 1

Popeye
Popeye

Reputation: 35900

Your approach is incorrect and It is better to use MONTHS_BETWEEN as it takes care of everything i.e. different number of days in the month and etc.

You can use MONTHS_BETWEEN as follows:

SELECT 
MONTHS_BETWEEN (TO_DATE('2020-07-07','YYYY-MM-DD'),TO_DATE('2019-08-01','YYYY-MM-DD'))
FROM dual

Upvotes: 1

Related Questions