SQL:根据两个日期之间的月份为记录创建多行

SQL: Create multiple rows for a record based on months between two dates

我的table有如下不同ID和不同开始和结束日期的记录
ID、开始日期、结束日期
1, 2017-02-14, 2018-11-05

我想写一个 SQL without using date dimension table 给出以下输出:基本上每个月在开始和结束日期之间有一个记录.

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

您必须生成日期并从中选择年份和月份

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

请使用以下查询示例:

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

这就是我所做的,效果非常好:

-- 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