Sql Teradata-将日期范围拆分为带有日期计数的月份列

Sql Teradata-将日期范围拆分为带有日期计数的月份列,sql,teradata,Sql,Teradata,我需要将一个季度内的不同日期范围拆分为月份列,其中只包含该月份实际使用的天数。每个记录(范围)都会不同 示例: 表格 Record_ID Start_Date End_Date 1 10/27 11/30 2 11/30 12/14 3 12/14 12/31 Range 1 = 10/5 to 12/14 Range 2 = 11/20 to 12/31 Range 3 = 10/28 to 12/2 输

我需要将一个季度内的不同日期范围拆分为月份列,其中只包含该月份实际使用的天数。每个记录(范围)都会不同

示例

表格

Record_ID Start_Date  End_Date
1         10/27       11/30
2         11/30       12/14
3         12/14       12/31

Range 1 = 10/5 to 12/14
Range 2 = 11/20 to 12/31
Range 3 = 10/28 to 12/2
输出

范围1

Oct    Nov    Dec 
27     30     14

首先加入日历,获取范围内的所有日期,并获取每个月的天数(包括整月,开始日期和结束日期中未提及)

然后在每个范围的列中对每个月进行汇总

create table SplitDateRange ( Range bigint, Start_Date date,  End_Date date );
insert into SplitDateRange values ( 1, '2018-10-05', '2018-12-14' );
insert into SplitDateRange values ( 2, '2018-11-20', '2018-12-31' );
insert into SplitDateRange values ( 3, '2018-10-28', '2018-12-02' );

select
          Range
        , sum(case when mon = 10 then days else 0 end) as "Oct"
        , sum(case when mon = 11 then days else 0 end) as "Nov"
        , sum(case when mon = 12 then days else 0 end) as "Dec"
from (
        select
                Range
                , extract(MONTH from C.calendar_date) as mon
                , max(C.calendar_date) - min(calendar_date) +1 as days
        from Sys_Calendar.CALENDAR as C
        inner join SplitDateRange as DR
        on C.calendar_date between DR.Start_Date and DR.End_Date
        group by 1,2
) A
group by Range
order by Range
;

首先加入日历,获取范围内的所有日期,并获取每个月的天数(包括整月,开始日期和结束日期中未提及)

然后在每个范围的列中对每个月进行汇总

create table SplitDateRange ( Range bigint, Start_Date date,  End_Date date );
insert into SplitDateRange values ( 1, '2018-10-05', '2018-12-14' );
insert into SplitDateRange values ( 2, '2018-11-20', '2018-12-31' );
insert into SplitDateRange values ( 3, '2018-10-28', '2018-12-02' );

select
          Range
        , sum(case when mon = 10 then days else 0 end) as "Oct"
        , sum(case when mon = 11 then days else 0 end) as "Nov"
        , sum(case when mon = 12 then days else 0 end) as "Dec"
from (
        select
                Range
                , extract(MONTH from C.calendar_date) as mon
                , max(C.calendar_date) - min(calendar_date) +1 as days
        from Sys_Calendar.CALENDAR as C
        inner join SplitDateRange as DR
        on C.calendar_date between DR.Start_Date and DR.End_Date
        group by 1,2
) A
group by Range
order by Range
;

与@ULick使用sys_calendar.calendar的回答类似,但更简洁一点:

CREATE VOLATILE MULTISET TABLE datetest (record_id int, start_date date, end_date date) ON COMMIT PRESERVE ROWS;

INSERT INTO datetest VALUES (1, '2017-10-05', '2017-12-14');
INSERT INTO datetest VALUES (2, '2017-11-20','2017-12-31');

SELECT record_id, 
    SUM(CASE WHEN month_of_year = 10 THEN 1 ELSE 0 END) as October,
    SUM(CASE WHEN month_of_year = 11 THEN 1 ELSE 0 END) as November,
    SUM(CASE WHEN month_of_year = 12 THEN 1 ELSE 0 END) as December
FROM datetest
    INNER JOIN sys_calendar.calendar cal 
        ON cal.calendar_date BETWEEN start_date and end_date
GROUP BY record_id;

DROP TABLE datetest;
因为问题中提到了季度(我不确定它在这里是如何联系的),所以在系统日历中还有
Quarter\u of \u year
month\u of \u Quarter
,可以进一步细分


此外,如果您使用的是16.00+版本,则PIVOT功能可能有助于消除此处的案例陈述。

类似于@ULick使用sys\u calendar.calendar的回答,但更简洁一点:

CREATE VOLATILE MULTISET TABLE datetest (record_id int, start_date date, end_date date) ON COMMIT PRESERVE ROWS;

INSERT INTO datetest VALUES (1, '2017-10-05', '2017-12-14');
INSERT INTO datetest VALUES (2, '2017-11-20','2017-12-31');

SELECT record_id, 
    SUM(CASE WHEN month_of_year = 10 THEN 1 ELSE 0 END) as October,
    SUM(CASE WHEN month_of_year = 11 THEN 1 ELSE 0 END) as November,
    SUM(CASE WHEN month_of_year = 12 THEN 1 ELSE 0 END) as December
FROM datetest
    INNER JOIN sys_calendar.calendar cal 
        ON cal.calendar_date BETWEEN start_date and end_date
GROUP BY record_id;

DROP TABLE datetest;
因为问题中提到了季度(我不确定它在这里是如何联系的),所以在系统日历中还有
Quarter\u of \u year
month\u of \u Quarter
,可以进一步细分


此外,如果您使用的是16.00+版本,则PIVOT功能可能有助于消除此处的CASE语句。

不同的方法是,通过应用Teradata Expand on功能创建时间序列,避免交叉连接到日历。更多文本,但对于更大的表格/范围应更有效:

SELECT record_id,
   Sum(CASE WHEN mth = 10 THEN days_in_month ELSE 0 END) AS October,
   Sum(CASE WHEN mth = 11 THEN days_in_month ELSE 0 END) AS November,
   Sum(CASE WHEN mth = 12 THEN days_in_month ELSE 0 END) AS December
FROM 
 ( -- this Derived Table simply avoids repeating then EXTRACT/INTERVAL calculations (can't be done directly in the nested Select)
   SELECT record_id,
      Extract(MONTH From Begin(expanded_pd)) AS mth, 
      Cast((INTERVAL( base_pd P_INTERSECT expanded_pd) DAY) AS INT) AS days_in_month
   FROM 
    (
      SELECT record_id,
         PERIOD(start_date, end_date+1) AS base_pd, 
         expanded_pd
      FROM datetest
        -- creates one row per month
      EXPAND ON base_pd AS expanded_pd BY ANCHOR PERIOD Month_Begin
    ) AS dt
 ) AS dt
GROUP BY 1

不同的方法是,通过应用Teradata扩展功能来创建时间序列,从而避免交叉连接到日历。更多文本,但对于更大的表格/范围应更有效:

SELECT record_id,
   Sum(CASE WHEN mth = 10 THEN days_in_month ELSE 0 END) AS October,
   Sum(CASE WHEN mth = 11 THEN days_in_month ELSE 0 END) AS November,
   Sum(CASE WHEN mth = 12 THEN days_in_month ELSE 0 END) AS December
FROM 
 ( -- this Derived Table simply avoids repeating then EXTRACT/INTERVAL calculations (can't be done directly in the nested Select)
   SELECT record_id,
      Extract(MONTH From Begin(expanded_pd)) AS mth, 
      Cast((INTERVAL( base_pd P_INTERSECT expanded_pd) DAY) AS INT) AS days_in_month
   FROM 
    (
      SELECT record_id,
         PERIOD(start_date, end_date+1) AS base_pd, 
         expanded_pd
      FROM datetest
        -- creates one row per month
      EXPAND ON base_pd AS expanded_pd BY ANCHOR PERIOD Month_Begin
    ) AS dt
 ) AS dt
GROUP BY 1

表是什么样子的?它只有:Record_ID、Start_Date、End_Date开始和结束之间的时间段是否会跨越到下一年(如果是,将如何显示)。从开始到结束的时间段是否超过1年(这里会如何显示)?您的范围都重叠,我不知道您的输出代表什么。你到底想做什么?这个表是什么样子的?它只有:Record\u ID,Start\u Date,End\u Date开始和结束之间的时间段是否会跨越到下一年(如果是,将如何显示)。从开始到结束的时间段是否超过1年(这里会如何显示)?您的范围都重叠,我不知道您的输出代表什么。你到底想做什么?编辑后,我不明白第一个(添加的)表与预期结果的关系。编辑后,我不明白第一个(添加的)表与预期结果的关系。谢谢!工作得很好。正是我需要的,我就是看不见。谢谢!工作得很好。正是我需要的,我就是看不见。谢谢你!我真的很感激。谢谢你!我真的很感激。