Home > Blockchain >  Generate all months dynamically between two dates on a table
Generate all months dynamically between two dates on a table

Time:02-03

I have a table like this:

NAME INT_VALUE START END
One 100 2013-11-16 2014-11-16

The goal is to output like this:

NAME INT_VALUE START END INTERVAL
One 100 2013-11-16 2014-11-16 11-2013
One 100 2013-11-16 2014-11-16 12-2013
One 100 2013-11-16 2014-11-16 1-2014
One 100 2013-11-16 2014-11-16 2-2014

I've started using this. But I am not really sure how I'd use the START and END dates on the table to determine the start and end to calculate the list of months between.

SELECT START, calendar, COUNT(1)
FROM table1 AS t1
    RIGHT JOIN (SELECT row_number() OVER (ORDER BY SEQ4()) AS MONTHS
                ,      TO_DATE(DATEADD(MONTH, MONTHS, '2019-05-01')) AS calendar
                FROM TABLE(GENERATOR(rowcount=>80)))
            ON t1.START = calendar
GROUP BY 1, 2
ORDER BY 2, 1
;

The goal here is to associate the int value with every month from the beginning to the end of the range.

CodePudding user response:

WITH RECURSIVE
cte AS ( SELECT name, int_value, start, `end`, 
                1 rownum, DATE_FORMAT(start, '%m-%Y') `interval`
         FROM source_table
         UNION ALL
         SELECT name, int_value, start, `end`, 
                1   rownum, DATE_FORMAT(start   INTERVAL rownum MONTH, '%m-%Y')
         FROM cte
         WHERE start   INTERVAL rownum - 1 MONTH < `end` )
         
SELECT name, int_value, start, `end`, `interval`
FROM cte
ORDER BY rownum;

https://dbfiddle.uk/?rdbms=mysql_8.0&fiddle=bdd028a7755fdcb8296df2301baeb295

If you do not need in leading zeros in month numbers then use '%c-%Y' pattern.

CodePudding user response:

so moving the range of numbers out to it's own CTE to separate things, we now have a big list of 80 numbers (it could be bigger).

Then we find the number of months between the start/end and join to that many rows. And do the math to turn the range into the select part:

WITH range_of_numbers AS (
    SELECT 
        row_number() OVER (ORDER BY SEQ4())-1 AS rn
    FROM TABLE(GENERATOR(rowcount=>80))
)
SELECT 
    t1.name, 
    t1.int_value, 
    t1.start,
    t1.end,
    DATEADD(MONTH, r.rn, t1.start) as interval
FROM table1 AS t1
JOIN range_of_numbers as r
    ON date_diff('month', t1.START, t1.end) <= between r.rn
ORDER BY 2,1,3;

Another option is it build a long range DATE table

CREATE TABLE dates AS 
SELECT 
     DATEADD(MONTH, row_number() OVER (ORDER BY SEQ4())-1, '1980-01-01') as month_date
FROM TABLE(GENERATOR(rowcount=>8000))

Then we use BETWEEN to get the inclusive values in the (start,end) range would become:

FROM table1 AS t1
JOIN dates as d
    ON d.month_date BETWEEN t1.START AND t1.end
  •  Tags:  
  • Related