Skip to Main Content
  • Questions
  • Converting quarter number to dates of months of this quarter

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Ivan.

Asked: March 15, 2017 - 5:46 pm UTC

Last updated: March 23, 2017 - 3:37 am UTC

Version: 11.2

Viewed 1000+ times

You Asked

Hi Tom!

I have a table containing a column with a QUARTER of the year (1, 2, 3, 4). I'd like to multiply each row into another table while substituting the quarter column with two columns - containing the DATE of the FIRST and the LAST day of each of the 3 months of each quarter sequentially. E.g. each row with quarter = 1 yields 3 rows with field values as follows:
FIRST------------LAST
'01.01.2017', '31.01.2017'
'01.02.2017', '28.01.2017'
'01.03.2017', '31.03.2017'

and so on.

How'd I go about that?

Thanks in advance.

and Chris said...

You can use add_months to increment a date by the number of months. So you just need to calculate the number of months to add.

If you have a row/quarter, cross join this with a three row table. Then to find the start of each month, you:

- Subtract 1 from the quarter, then multiply by 3. Then add the "month within the quarter" - 1

The end date of each is similar, but you don't need to subtract one from the "month within the quarter". Just minus a day from the result of add_months:

with rws as (
  select 2017 yr, 1 qtr from dual union all
  select 2017 yr, 2 qtr from dual union all
  select 2017 yr, 3 qtr from dual union all
  select 2017 yr, 4 qtr from dual
), qmths as (
  select level-1 q from dual connect by level <= 3
)
  select yr, qtr,
         add_months(to_date('01-01-' || yr, 'dd-mm-yyyy'), ((qtr-1) * 3) + q ) st,
         add_months(to_date('01-01-' || yr, 'dd-mm-yyyy'), ((qtr-1) * 3) + q + 1 )-1 en
  from   rws
  cross  join qmths
  order  by st;

YR     QTR  ST                    EN                    
2,017  1    01-JAN-2017 00:00:00  31-JAN-2017 00:00:00  
2,017  1    01-FEB-2017 00:00:00  28-FEB-2017 00:00:00  
2,017  1    01-MAR-2017 00:00:00  31-MAR-2017 00:00:00  
2,017  2    01-APR-2017 00:00:00  30-APR-2017 00:00:00  
2,017  2    01-MAY-2017 00:00:00  31-MAY-2017 00:00:00  
2,017  2    01-JUN-2017 00:00:00  30-JUN-2017 00:00:00  
2,017  3    01-JUL-2017 00:00:00  31-JUL-2017 00:00:00  
2,017  3    01-AUG-2017 00:00:00  31-AUG-2017 00:00:00  
2,017  3    01-SEP-2017 00:00:00  30-SEP-2017 00:00:00  
2,017  4    01-OCT-2017 00:00:00  31-OCT-2017 00:00:00  
2,017  4    01-NOV-2017 00:00:00  30-NOV-2017 00:00:00  
2,017  4    01-DEC-2017 00:00:00  31-DEC-2017 00:00:00 

Rating

  (3 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Got it.

A reader, March 20, 2017 - 3:40 am UTC

Hello, Chris and thank you for the quick reply!

Actually I did understood that this will require a 3 row table to join on, but thought there could be some special magic like in TOM's advice on how to turn a string "1, 2, 3" into an in list via a CONNECT BY clause and presto here it is again, some coincidence :) Though admittedly its use is more trivial here.)
Chris Saxon
March 20, 2017 - 2:49 pm UTC

Well you could use a "trick" to create four rows. But splitting a string or similar adds unnecessary complexity.

Follow up

Ivan, March 20, 2017 - 4:17 pm UTC

No no no, Chris, maybe I didn't make myself clear - I've mentioned splitting string with a connect by only as an example of TOM's unending wisdom :) Has nothing to do with my case whatsoever :)
Actually I could use any of our tables with >= 3 rows, which we have in abundance - while the dual+connect by way is more reliable obviously.

(can I actually answer to an answer to a review rather than submitting a new review? sorry I'm new to posting on AskTOM)
Connor McDonald
March 22, 2017 - 2:15 am UTC

But isnt that exactly what Chris has done with the demo he gave you ?

with rws as (
  select 2017 yr, 1 qtr from dual union all
  select 2017 yr, 2 qtr from dual union all
  select 2017 yr, 3 qtr from dual union all
  select 2017 yr, 4 qtr from dual
), qmths as (                                             <=====
  select level-1 q from dual connect by level <= 3        <=====
)
...
...


Yep exactly

Ivan, March 22, 2017 - 5:49 pm UTC

I wasn't complaining, merely thanking TOM for your helpful advice.) Cheers!
Connor McDonald
March 23, 2017 - 3:37 am UTC

glad we could help :-)