SQL优化的计算聚合时间跨度的方法

时间:2013-05-07 19:42:25

标签: sql sql-server

我有一个包含 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本地,高效的方式来实现这个?

1 个答案:

答案 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的索引,则会提高效果。