【问题标题】:How to split a date range into separate years如何将日期范围分成不同的年份
【发布时间】:2021-10-03 12:31:58
【问题描述】:

我有一个 Start_Date 和 End_Date。我想把它分成几个范围。 示例:

Emp_Name Start_Dtm End_Dtm
xyz 2020-09-16 2023-09-15
ABC 2020-06-10 2021-10-12

我想要以下格式:

Emp_Name Start_Dtm End_Dtm
xyz 2020-09-16 2020-12-31
xyz 2021-01-01 2021-12-31
xyz 2022-01-01 2022-12-31
xyz 2023-01-01 2023-09-15
ABC 2020-06-10 2020-12-31
ABC 2021-01-01 2021-10-12

【问题讨论】:

  • 我建议投资一个日历表,那么这很简单。
  • 这能回答你的问题吗? Split date range into months (Using CTE) 这个想法字面意思是一样的,只是你想要几年而不是几个月,如果你花时间去理解它,你应该能够轻松实现它。

标签: sql sql-server date


【解决方案1】:

这使用了一个带有年份的表格,这是一种硬编码。我通常会使用整个日期维度。

declare @y table (yr int)

insert into @y values(2018),(2019),(2020),(2021),(2022),(2023)

declare @d table (person varchar(100), startDte date, endDate date)

insert into @d values
('xyz', '2020-09-16',   '2023-09-15')
,('ABC',    '2020-06-10',   '2021-10-12')

select person
    ,startDte = iif(year(startDte)=ca.yr,startDte,Cast(cast(ca.yr as varchar(4)) + '0101' as date))
    ,endDate = iif(year(endDate) = ca.yr,endDate,cast(cast(ca.yr as varchar(4)) + '1231' as date))
from @d
    cross apply (select yr from @y where yr between year(startDte) and year(endDate)) ca
order by person,startDte

交叉应用将为开始日期和结束日期之间的每一年创建一行。然后您使用那一年来确定为详细记录选择/创建的日期。

结果:

person  startDte    endDate
ABC 2020-06-10  2020-12-31
ABC 2021-01-01  2021-10-12
xyz 2020-09-16  2020-12-31
xyz 2021-01-01  2021-12-31
xyz 2022-01-01  2022-12-31
xyz 2023-01-01  2023-09-15

【讨论】:

    【解决方案2】:

    由于您没有任何日历表,为了从 Start_Dtm 和 End_Dtm 生成数字系列,我使用了 master..[spt_values] 表并将其与 cross apply 一起用于创建必要的新行。 然后使用公用表表达式和 case when 表达式,很容易做到你所要求的。

    DB-Fiddle:

     create table yourtable (Emp_Name varchar(50), Start_Dtm date, End_Dtm date);
     insert into yourtable values('xyz', '2020-09-16','2023-09-15');
     insert into yourtable values('ABC', '2020-06-10','2021-10-12');
    

    查询:

     with cte as
     (
        select Emp_Name, Start_Dtm, End_Dtm, number,count(*)over(partition by Emp_Name, Start_Dtm, End_Dtm )cnt,
        DATEFROMPARTS(year(start_dtm)+number-1,1,1)New_Start_Dtm,
        DATEFROMPARTS(year(start_dtm)+number-1,12,31)New_End_Dtm 
        From yourtable 
        cross apply (select distinct number from master..[spt_values] 
        WHERE number BETWEEN 1 and 1+year(End_Dtm)-Year(Start_Dtm))as calendar (Number)
     )
     select Emp_Name, 
     (case when number=1 then Start_Dtm else New_Start_Dtm end)  Start_Dtm,
     (case when cnt>number then New_End_Dtm else End_Dtm end)  End_Dtm
     from cte
    

    输出:

    Emp_Name Start_Dtm End_Dtm
    ABC 2020-06-10 2020-12-31
    ABC 2021-01-01 2021-10-12
    xyz 2020-09-16 2020-12-31
    xyz 2021-01-01 2021-12-31
    xyz 2022-01-01 2022-12-31
    xyz 2023-01-01 2023-09-15

    db小提琴here

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-07
      相关资源
      最近更新 更多