SQL将事件列表转换为持续时间(MSSQL 2008)

时间:2014-01-23 08:26:02

标签: sql sql-server sql-server-2008

假设我有一张包含各种事件及其开始时间的表格:

EventTime              EventCode         EventDescription
---------              ---------         ----------------
2014-01-23 00:03:32    430               Running
2014-01-23 00:04:35    430               Running
2014-01-23 00:06:37    430               Running
2014-01-23 00:11:45    430               Running
2014-01-23 00:32:46    721               Stopped
2014-01-23 00:34:49    721               Stopped
2014-01-23 00:41:52    430               Running
2014-01-23 01:03:54    721               Stopped    
2014-01-23 01:04:55    430               Running

根据这些数据,我想得到所有间隔的开始时间和持续时间。含义,eventCode 721的记录的startTime和eventCode 430的第一个连续事件的startTime,反之亦然,如下所示:

START                 END                   STATUS
-----------           ----------            ----------------
2014-01-23 00:03:32   2014-01-23 00:32:46   Running
2014-01-23 00:32:46   2014-01-23 00:41:52   Stopped
2014-01-23 00:41:52   2014-01-23 01:03:54   Running
2014-01-23 01:03:54   2014-01-23 01:04:55   Stopped

我已经看到了OVER语法的用法,但在我看到的例子中,它被用于数据集中的连续行。表a可以具有许多相同的状态。

如示例中那样转换数据的最佳(也是最高效)方法是什么?谢谢!

2 个答案:

答案 0 :(得分:3)

一种方法

WITH cte AS 
(
  SELECT eventcode, eventdescription, MIN(eventtime) starttime, MAX(eventtime) endtime,
         ROW_NUMBER() OVER (ORDER BY MIN(eventtime)) rnum
    FROM
  (
    SELECT t.*,
           ROW_NUMBER() OVER (ORDER BY eventtime) rnum,
           ROW_NUMBER() OVER (PARTITION BY eventcode ORDER BY eventtime) grnum
      FROM table1 t
  ) q
   GROUP BY eventcode, eventdescription, rnum - grnum
)
SELECT t1.starttime, t2.starttime endtime, t1.eventdescription status
  FROM cte t1 JOIN cte t2
    ON t1.rnum = t2.rnum - 1
 ORDER BY starttime, endtime

输出:

|                      STARTTIME |                        ENDTIME |  STATUS |
|--------------------------------|--------------------------------|---------|
| January, 23 2014 00:03:32+0000 | January, 23 2014 00:32:46+0000 | Running |
| January, 23 2014 00:32:46+0000 | January, 23 2014 00:41:52+0000 | Stopped |
| January, 23 2014 00:41:52+0000 | January, 23 2014 01:03:54+0000 | Running |
| January, 23 2014 01:03:54+0000 | January, 23 2014 01:04:55+0000 | Stopped |

这是 SQLFiddle 演示

答案 1 :(得分:2)

这类似于peterm的答案,只少了一个ROW_NUMBER ......

您可以将LEFT联接更改为INNER:

WITH cte (EventTime, EventCode, EventDescription, rn, rn2) AS 
 (
   SELECT
      EventTime, EventCode, EventDescription,
      ROW_NUMBER() OVER (ORDER BY EventTime) AS rn,
      ROW_NUMBER() OVER (PARTITION BY EventCode ORDER BY EventTime) AS rn2
   FROM Table1
 )
SELECT MIN(t1.EventTime), MAX(t2.EventTime), t1.EventDescription
FROM cte AS t1 LEFT JOIN cte AS t2
ON t2.rn = t1.rn+1
GROUP BY t2.rn-t1.rn2, t1.EventDescription
ORDER BY 1