将日期拆分为间隔
Posted
技术标签:
【中文标题】将日期拆分为间隔【英文标题】:Split date into intervals 【发布时间】:2021-03-10 10:49:10 【问题描述】:我正在尝试建立一对多的日期关系,因此将我当前的日期范围划分为每半年一次。
桶:0-6months、6-12months、12-18months、18-24months、+24months(考虑到重叠)
例子:
表格
Name | Start_Date | End_Date |
---|---|---|
XYZ | 2020-01-01 | 2022-01-01 |
期望的输出
Name | Start_Date | End_Date | Interval_Start_Date | Interval_End_Date | Date_Bucket |
---|---|---|---|---|---|
XYZ | 2020-01-01 | 2022-01-01 | 2020-01-01 (Start_Date) | 2020-06-30 | 0-6months |
XYZ | 2020-01-01 | 2022-01-01 | 2020-07-01 | 2020-12-31 | 6-12months |
XYZ | 2020-01-01 | 2022-01-01 | 2021-01-01 | 2021-06-30 | 12-18months |
XYZ | 2020-01-01 | 2022-01-01 | 2021-07-01 | 2021-12-31 | 18-24months |
XYZ | 2020-01-01 | 2022-01-01 | 2022-01-01 | 2022-01-01 (End_Date) | +24months |
我现在的代码:
select
a.name,
a.start_date,
a.end_date
from table a
它输出 [Table],还有更多行 - 目前仅在示例中显示一个。
【问题讨论】:
范围可以有多大?总是 2 年、2 年或更短时间、20 年? @Larnu 一些范围可能超过 1000 天,因此超过 30 个月。所有这些范围都将被纳入 +24 个月的桶中。大多数在0-24个月之间。 2 年只是一个涵盖所有方面的示例。 另外,我必须承认,您的日期界限感觉“错误”。我希望第二个边界从2020-06-01
开始,而之前的结束在2020-05-31
。否则,您的第一个边界是 6 个月零 1 天,而其余的 6 个月。
其实第一个边界只有5个月?
@Larnu 啊,我的错,我已经相应地编辑了表格。它涵盖了现在的重叠和错误统计
【参考方案1】:
这给了您预期的结果,但是,您的存储桶的长度奇怪地不同。例如,第一个存储桶只有 5 个月和一天的长度,而其余的是 6 个月。因此,我给出了一个给出预期结果的答案,它不反映了将结果放入 6 个月桶的描述。虽然如果这是您的 true 要求,您应该能够轻松更改此设置:
CREATE TABLE dbo.YourTable ([Name] varchar(3),
StartDate date,
EndDate date);
GO
INSERT INTO dbo.YourTable
VALUES ('XYZ','2020-01-01','2022-01-01'),
('XYZ','2020-01-01','2021-01-01');
GO
WITH CTE AS(
SELECT YT.Name,
YT.StartDate,
YT.EndDate,
CASE V.IntervalStart WHEN 0 THEN YT.StartDate
ELSE DATEADD(DAY,1,DATEADD(MONTH,V.IntervalStart,YT.StartDate))
END AS IntervalStartDate,
CASE V.IntervalStart WHEN 0 THEN DATEADD(MONTH,V.IntervalEnd,YT.StartDate)
ELSE ISNULL(DATEADD(DAY,1,DATEADD(MONTH,V.IntervalEnd,YT.StartDate)),YT.EndDate)
END AS IntervalEndDate,
V.IntervalStart,
V.IntervalEnd
FROM dbo.YourTable YT
CROSS APPLY(VALUES(0,5),(5,11),(11,17),(17,23),(23,NULL))V(IntervalStart,IntervalEnd))
SELECT Name,
StartDate,
EndDate,
IntervalStartDate,
CASE WHEN IntervalEndDate > EndDate THEN EndDate ELSE IntervalEndDate END AS IntervalEndDate,
CASE WHEN IntervalEnd IS NULL THEN '+24months' ELSE CONCAT(IntervalStart,'-',IntervalEnd,'months') END AS DateBucket
FROM CTE
WHERE IntervalStartDate < EndDate;
GO
DROP TABLE dbo.YourTable;
db<>fiddle
【讨论】:
【参考方案2】:您可以尝试这样的事情,使用公用表表达式递归:
;with Raw_Data as
(
select Name, Start_Date, End_Date,
Start_Date as IntervalStartDate,
DATEADD(M,5,Start_Date) as IntervalEndDate,
1 as Interval
from YourTable
union all
select Name, Start_Date, End_Date,
IntervalEndDate+1 as IntervalStartDate,
IIF(Interval=4,End_Date, DATEADD(M,6,IntervalEndDate)) as IntervalEndDate,
Interval+1 as Interval
from Raw_Data where Interval <= 4
)
select Name, Start_Date, End_Date,
IIF(IntervalStartDate < End_Date, IntervalStartDate, NULL) as IntervalStartDate,
IIF(IntervalEndDate < End_Date, IntervalEndDate, End_Date) as IntervalEndDate,
Interval
from Raw_Data
where IntervalStartDate < End_Date
order by Name, Interval
【讨论】:
以上是关于将日期拆分为间隔的主要内容,如果未能解决你的问题,请参考以下文章