将日期拆分为间隔

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

【讨论】:

以上是关于将日期拆分为间隔的主要内容,如果未能解决你的问题,请参考以下文章

熊猫如何按间隔按列拆分数据帧

熊猫如何按间隔按列拆分数据帧

JAVA中将一个时间段按固定间隔拆分为List

将日期时间列拆分为日期和时间变量

Matlab中tabel如何按照日期列拆分

Impala:根据日期和时间将单行拆分为多行