我有一个包含 n 历史记录条目的表格,用于记录活动/非活动的更改。
[Id] [ParentId] [Date] [Status]
<guid> 0 2013-05-03 15:51:24.810 'Active'
<guid> 0 2013-05-03 15:52:10.773 'Inactive'
<guid> 0 2013-05-03 15:54:26.710 'Active'
<guid> 0 2013-05-03 17:09:27.327 'Inactive'
我正在尝试确定该项目在整个历史记录中处于“活动”状态的时间。使用光标迭代历史记录并使用DATEDIFF
来计算它的表现非常糟糕。我试图避免使用SQLCLR,但可能在内存中相当便宜地做到这一点......有没有人知道一个良好的SQL本地,高效的方式来实现这个?
答案 0 :(得分:2)
关键的想法是在给定的有效记录之后获得下一个非活动记录。
如果您使用的是SQL Server 2012,则可以使用lead()
功能。否则,我认为相关子查询是表示需要完成的最简单的方法。 (您也可以使用明确的join
执行此操作,我认为这更清楚。)
select guid, sum(datediff(ms, t.[date], t.nextInactive)) as duration_ms
from (select t.*,
(select min([date])
from t t2
where t2.guid = t.guid and t2.[date] > t.[date] and t2.status = 'Inactive'
) as nextInactive
from t
where t.status = 'Active'
) t
group by guid
获得下一个非活动记录后,只需取差(在这种情况下以毫秒为单位)并加上值。
如果最后一条记录是活动记录,则会被忽略。如果您想要计算,那么您需要在外部查询中使用coalesce(t.nextInactive, <some value here>)
。
如果您有guid, status, date
的索引,则会提高效果。