使用SQL将行和分组设置为下一行中的值

时间:2012-08-30 13:55:40

标签: sql sql-server-2008 row grouping

我有一个数据表,如下所示:

ID |   EventName   |     StartTime      |     EndTime     |
 1       Event1      2012-08-08 10:00:00         ???
 2       Event1      2012-08-08 10:15:00         ???
 3       Event1      2012-08-08 11:35:00         ???
 4       Event2      2012-08-08 11:50:00         ???
 5       Event2      2012-08-08 12:05:00         ???
 6       Event1      2012-08-08 12:23:00         ???
 7       Event1      2012-08-08 12:40:00         ???
 8       Event2      2012-08-08 13:47:00         ???

此数据旨在显示事件1从10 OClock开始并一直运行到11:50(事件2的开始时间)。事件2然后从11:50运行到12:23,此时事件1再次启动。

我想对相同事件的块进行分组,并将事件的结束时间设置为下一个事件的开始时间。结果表应如下所示:

EventName   |        StartTime         |        EndTime        |
 Event1         2012-08-08 10:00:00        2012-08-08 11:50:00 
 Event2         2012-08-08 11:50:00        2012-08-08 12:23:00
 Event1         2012-08-08 12:23:00        2012-08-08 13:47:00
 Event2         2012-08-08 13:47:00        NULL

3 个答案:

答案 0 :(得分:3)

正如有人说使用游标会是一个很好的方法 - 我测试了这个并在表变量中提供了一个测试表。请将它放在查询窗口中并测试它,用表名替换变量。

@Events包含:

活动1 - 10:00

活动1 - 10:15

事件1 - 11:35

事件2 - 11:50

事件1 - 11:55

输出结果为:

活动1 10:00 11:50

事件2 11:50 11:55

事件1 11:55 NULL

DECLARE @Events AS TABLE
    (
      ID INT IDENTITY(1, 1) ,
      EventName VARCHAR(50) ,
      StartTime DATETIME ,
      EndTime DATETIME
    )

INSERT  INTO @Events
        ( EventName ,
          StartTime ,
          EndTime
        )
VALUES  ( 'Event1' ,
          '2012-08-08 10:00:00' ,
          NULL  
        )
INSERT  INTO @Events
        ( EventName ,
          StartTime ,
          EndTime
        )
VALUES  ( 'Event1' ,
          '2012-08-08 10:15:00' ,
          NULL  
        )
INSERT  INTO @Events
        ( EventName ,
          StartTime ,
          EndTime
        )
VALUES  ( 'Event1' ,
          '2012-08-08 11:35:00' ,
          NULL  
        )
INSERT  INTO @Events
        ( EventName ,
          StartTime ,
          EndTime
        )
VALUES  ( 'Event2' ,
          '2012-08-08 11:50:00' ,
          NULL  
        )
        INSERT  INTO @Events
        ( EventName ,
          StartTime ,
          EndTime
        )
VALUES  ( 'Event1' ,
          '2012-08-08 11:55:00' ,
          NULL  
        )
DECLARE @CurrentEvent AS VARCHAR(100) ,
    @CurrentStartTime AS DATETIME ,
    @EndTime AS DATETIME ,
    @CursorEvent AS VARCHAR(100) ,
    @EventsToDelete AS INT
SET @EventsToDelete = ( SELECT  COUNT(*)
                        FROM    @Events
                      )
SELECT TOP 1
        @CurrentEvent = EventName ,
        @CurrentStartTime = StartTime
FROM    @Events
DECLARE EventsCursor CURSOR
FOR
    SELECT  EventName ,
            StartTime
    FROM    @Events
    ORDER BY EndTime ASC
OPEN EventsCursor
FETCH NEXT FROM EventsCursor INTO @CursorEvent, @EndTime
WHILE @@FETCH_STATUS = 0 
    BEGIN
        IF NOT @CursorEvent = @CurrentEvent 
            BEGIN
                INSERT  INTO @Events
                        ( EventName ,
                          StartTime ,
                          EndTime
                        )
                VALUES  ( @CurrentEvent ,
                          @CurrentStartTime ,
                          @EndTime  
                        )
                SET @CurrentEvent = @CursorEvent
                SET @CurrentStartTime = @EndTime
            END
           FETCH NEXT FROM EventsCursor INTO @CursorEvent, @EndTime 
    END
CLOSE EventsCursor
DEALLOCATE EventsCursor

DELETE  FROM @Events
WHERE   ID < @EventsToDelete

SELECT * FROM @Events ORDER BY StartTime

SQL Fiddle

答案 1 :(得分:0)

您可以使用光标一次获取每一行。

获取时:

  1. 从第一个获取的行获取eventname和starttime
  2. 从第一个获取的行获取具有不同事件名称的结束时间(此行也作为下一个事件名称和stattime)。
  3. #temptable
  4. 中插入eventname,starttime和endtime

    在决赛中,选择#temptable

    中的行

答案 2 :(得分:0)

有趣的问题: 这应该工作,虽然我没有测试它(EventsTable是表的名称)

   select eventname,starttime,endtime
   from(
    select first.eventname eventname , min(second.starttime,first.starttime) starttime,                 second.eventname secondevent,first.starttime endtime
    from eventstable first, eventstable second where first.id=(second.id-1)
    ) where eventname != secondevent