Teradata - 将日期范围拆分为包含日计数的月份列

时间:2018-02-20 16:35:40

标签: 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

输出

范围1

Oct    Nov    Dec 
27     30     14

3 个答案:

答案 0 :(得分:1)

首先加入日历以获取该范围内的所有日期,并获取每个月的天数(包括整月,在Start_Date和End_Date中未提及)。

然后在每个范围的列中汇总每个月。

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
;

答案 1 :(得分:1)

与@ 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(我不确定它在这里是如何关联的),所以sys_calendar中还有quarter_of_yearmonth_of_quarter可用于对此进行切片和切块。

此外,如果你在16.00+有PIVOT功能可以帮助摆脱CASE声明。

答案 2 :(得分:1)

不同的方法,通过应用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