1
votes

My table has records as below for different Id's and different start and end dates
ID, Startdate, Enddate
1, 2017-02-14, 2018-11-05

I want to write an SQL without using date dimension table that gives below output: Basically one record for each month between start and end date.

1, 2017, 02
1, 2017, 03
1, 2017, 04
1, 2017, 05
1, 2017, 06
1, 2017, 07
1, 2017, 08
1, 2017, 09
1, 2017, 10
1, 2017, 11
1, 2017, 12
1, 2018, 01
1, 2018, 02
1, 2018, 03
1, 2018, 04
1, 2018, 05
1, 2018, 06
1, 2018, 07
1, 2018, 09
1, 2018, 10
1, 2018, 11
3
Can you add more sample data? I don't see the connect between the single record you showed us and the expected output table. - Tim Biegeleisen
Basically one record for each month between start and end date. - Karthik Doure
Seriously consider handling issues of data display in application code - Strawberry
Are you using MySQL or Netezza? Please tag your questions correctly. - Gordon Linoff
I am using Netezza - Karthik Doure

3 Answers

2
votes

This is what I did and it worked like a charm:

-- sample data  
WITH table_data
AS (
    SELECT 1 AS id
        ,cast('2017-08-14' AS DATE) AS start_dt
        ,cast('2018-12-16' AS DATE) AS end_dt

UNION ALL

SELECT 2 AS id
    ,cast('2017-09-14' AS DATE) AS start_dt
    ,cast('2019-01-16' AS DATE) AS end_dt
)

-- find minimum date from the data  
,starting_date (start_date)
AS (
SELECT min(start_dt)
FROM TABLE_DATA
)

--get all months between min and max dates  
,all_dates
AS (
SELECT last_day(add_months(date_trunc('month', start_date), idx * 1)) month_date
FROM starting_date
CROSS JOIN _v_vector_idx
WHERE month_date <= add_months(start_date, abs(months_between((
                    SELECT min(start_dt) FROM TABLE_DATA), (SELECT max(end_dt) FROM TABLE_DATA))) + 1)
ORDER BY month_date
)
SELECT id  
,extract(year FROM month_date)  
,extract(month FROM month_date)  
,td.start_dt  
,td.end_dt  
FROM table_data td  
INNER JOIN all_dates ad  
    ON ad.month_date > td.start_dt  
        AND ad.month_date <= last_day(td.end_dt)  
ORDER BY 1  
    ,2  
1
votes

Please use below query example:

set @start_date = '2017-02-14';
set @end_date = LAST_DAY('2018-11-05');


WITH RECURSIVE date_range AS
(
select MONTH(@start_date) as month_, YEAR(@start_date) as year_, DATE_ADD(@start_date, INTERVAL 1 MONTH) as next_month_date
UNION
SELECT MONTH(dr.next_month_date) as month_, YEAR(dr.next_month_date) as year_, DATE_ADD(dr.next_month_date, INTERVAL 1 MONTH) as next_month_date
FROM date_range dr
where next_month_date <= @end_date
)
select month_, year_ from date_range 
order by next_month_date desc
0
votes

You have to generate date and from that have to pick year and month

select distinct year(date),month( date) from
(select  * from (
select 
 date_add('2017-02-14 00:00:00.000', INTERVAL n5.num*10000+n4.num*1000+n3.num*100+n2.num*10+n1.num DAY ) as date 
  from
(select 0 as num
   union all select 1
   union all select 2
   union all select 3
   union all select 4
   union all select 5
   union all select 6
   union all select 7
   union all select 8
   union all select 9) n1,
(select 0 as num
   union all select 1
   union all select 2
   union all select 3
   union all select 4
   union all select 5
   union all select 6
   union all select 7
   union all select 8
   union all select 9) n2,
(select 0 as num
   union all select 1
   union all select 2
   union all select 3
   union all select 4
   union all select 5
   union all select 6
   union all select 7
   union all select 8
   union all select 9) n3,
(select 0 as num
   union all select 1
   union all select 2
   union all select 3
   union all select 4
   union all select 5
   union all select 6
   union all select 7
   union all select 8
   union all select 9) n4,
(select 0 as num
   union all select 1
   union all select 2
   union all select 3
   union all select 4
   union all select 5
   union all select 6
   union all select 7
   union all select 8
   union all select 9) n5
) a
where date >'2017-02-14 00:00:00.000' and date < '2018-11-05'
) as t