计算数据集不同行中日期之间的日期差异

Posted

技术标签:

【中文标题】计算数据集不同行中日期之间的日期差异【英文标题】:Calculate date difference between dates in different rows of a dataset 【发布时间】:2019-05-21 07:21:32 【问题描述】:

表格如下所示:

CREATE TABLE [dbo].[HistDT](
    [ID] [bigint] NULL,
    [StartDtSK] [varchar](8) NULL,
    [StartDt] [datetime] NULL,
    [status] [nvarchar](30) NULL,
) ON [PRIMARY]

示例数据集:

ID | StartDtSK | StartDt              | Status |
1     20190520   20-05-2019 12:00:13      10
1     20190520   20-05-2019 10:00:00       5
1     20190414   14-04-2019 13:23:00       2
2     20190312   12-03-2019 10:03:00      10
2     20190308   08-03-2019 18:03:00       1
etc..   

我需要一个查询来显示每个状态所花费的天数。如果我继承的表有结束日期,那将很容易。然后,我将计算 datediff 并为列 status 值旋转。

也许我应该使用 ssis 创建一个新表,我将在其中添加一个 EndDt 列,该列将是最新添加的状态的 StartDt。 但是有没有办法在不创建另一个表的情况下做到这一点?

【问题讨论】:

添加几行样本表数据,并指定预期结果。 很难确定结束日期,因为我们不知道它可能是什么。我可以理解它的每个状态。您能否提供更多具有相同状态值的状态示例?为什么他们有相同的 ID? @Thomas :在我看来,他们试图保留某种状态变化的历史记录。每行的结束日期是下一行的开始日期。因此,如果它按开始日期降序排序的 id 进行分区,则对于 row_number 1,结束日期将为空。对于 row_number 2,结束日期将是 row_number 1 的开始日期。也会添加您要求的内容。 【参考方案1】:

SQL Server 2008

这不是很漂亮,我还没有针对所有用例进行测试。我希望你可以使用它或找到灵感。我相信有更好的方法:)

declare @table2 table (
    [ID] [bigint] NULL,
    [StartDtSK] [varchar](8) NULL,
    [StartDt] [datetime] NULL,
    [status] [nvarchar](30) NULL
) 

insert into @table2

values
(1 ,   '20190520','2019-05-20 12:00:13','10'),


(1 ,   '20190520','2019-05-20 10:00:00','5'),

(1 ,   '20190414','2019-04-14 13:23:00','2'),
(2,     '20190312',   '2019-03-12 10:03:00',      '10'),
(2 ,    '20190308',   '2019-03-08 18:03:00',       '1')

select *,DATEDIFF(dd,startdt,enddate) as TotalDAys from (
select x.ID,StartDtSK,Startdt,[Status],Enddate from (
select *,ROW_NUMBER() over(partition by id order by startdt) as rn from @table2
) x
cross apply ( select * from (select id,StartDt as Enddate,ROW_NUMBER() over(partition by id order by startdt) as rn2  from @table2 b
)f where (rn +1 = f.rn2 ) and x.id = f.id ) d

union all
select ID,StartDtSK,startdt,[Status],'9999-12-31' as Enddate from (
select *,ROW_NUMBER() over(partition by id order by startdt desc) as rn from @table2
)X where rn=1
)y 
order by id,startdt

没有交叉应用的 SQL Server 2008

这可能会更漂亮一点:)

select *,DATEDIFF(dd,startdt,enddate) as TotalDAys from (
select x.ID,StartDtSK,Startdt,[Status],case when Enddate is null then '9999-12-31' else Enddate end as Enddate from (
select *,ROW_NUMBER() over(partition by id order by startdt) as rn from @table2
) x
left join ( 
select * from (select id,StartDt as Enddate,ROW_NUMBER() over(partition by id order by startdt) as rn2  from @table2 b
)f  ) d on  (rn +1 = d.rn2 ) and x.id = d.id

)y 

SQL Server 2012 及更高版本:

这是你想要的吗?

declare @table2 table (
    [ID] [bigint] NULL,
    [StartDtSK] [varchar](8) NULL,
    [StartDt] [datetime] NULL,
    [status] [nvarchar](30) NULL
) 

insert into @table2

values
(1 ,   '20190520','2019-05-20 12:00:13','10'),


(1 ,   '20190520','2019-05-20 10:00:00','5'),

(1 ,   '20190414','2019-04-14 13:23:00','2')

select *,Datediff(dd,Startdt,Enddate) as TotalDays from (
select *,LAG(StartDt,1,'9999-12-31') over(partition by ID order by StartDT desc) as EndDate from @table2
)x

插入处理当前状态 (9999-12-31) 日期的规则

【讨论】:

版本标签是 SQL Server 2008。Lag 是在 2012 年引入的。 @ZoharPeled 很好发现 - 没看到:/ 这正是我所需要的,正如 Zohar 所说,代码必须与 sql server 2008 兼容 @Bonzay 我更新了我的代码 - 尝试看看它是否有效。这是一个很长的镜头。而且不是很漂亮。 @Bonzay 刚刚添加了带有左连接的新代码,而不是我的交叉应用:) 祝你有美好的一天【参考方案2】:

也许 LEAD 功能对您的问题很有用。

这样

IsNull(DateAdd(SECOND,-1,Cast(LEAD ([StartDt],1) OVER (PARTITION BY [status] ORDER BY [StartDt]) AS DATETIME)),getdate()) AS EndDate

【讨论】:

版本标签是 SQL Server 2008。Lead 是在 2012 年推出的。

以上是关于计算数据集不同行中日期之间的日期差异的主要内容,如果未能解决你的问题,请参考以下文章

sql查询计算不同列和相邻行的两个日期之间的差异

使用数据帧中的某些参数计算日期之间的差异

如何为行中的多个集合计算存储过程中两个日期之间的差异

100K+ 行数据集中的日期时间差(以秒为单位)

在mysql查询中使用php time()函数计算两个日期之间的差异

在 Swift 中计算两个日期之间的差异