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年(这里会如何显示)?您的范围都重叠,我不知道您的输出代表什么。你到底想做什么?编辑后,我不明白第一个(添加的)表与预期结果的关系。编辑后,我不明白第一个(添加的)表与预期结果的关系。谢谢!工作得很好。正是我需要的,我就是看不见。谢谢!工作得很好。正是我需要的,我就是看不见。谢谢你!我真的很感激。谢谢你!我真的很感激。