使用SQL 2008/2012计算状态之间的时间范围

时间:2012-10-17 05:46:54

标签: sql sql-server-2008 tsql sql-server-2008-r2

使用SQL 2008/2012计算状态之间的时间范围

我在下表中存储了学生的状态

+----+-----------+------------------+---------+---------+
| ID | PERSON_ID |    TIMESTAMP     | IN_HOME | STUDYNG |
+----+-----------+------------------+---------+---------+
|  1 |         1 | 17/10/2012 19:00 |       0 |       0 |
|  2 |         1 | 17/10/2012 19:02 |       1 |       0 |
|  3 |         1 | 17/10/2012 19:03 |       1 |       1 |
|  4 |         1 | 17/10/2012 19:04 |       1 |       1 |
|  5 |         1 | 17/10/2012 19:05 |       1 |       0 |
|  6 |         1 | 17/10/2012 19:10 |       0 |       0 |
|  7 |         1 | 17/10/2012 19:12 |       0 |       0 |
|  8 |         1 | 17/10/2012 19:20 |       1 |       0 |
|  9 |         1 | 17/10/2012 19:25 |       1 |       0 |
| 10 |         1 | 17/10/2012 19:26 |       1 |       1 |
| 11 |         1 | 17/10/2012 19:30 |       1 |       0 |
+----+-----------+------------------+---------+---------+

我想以两种方式产生结果来制作一些报告:

I:

+-----------+------------------+------------------+---------+---------+
| PERSON_ID |      START       |       END        | IN_HOME | STUDYNG |
+-----------+------------------+------------------+---------+---------+
|         1 | 17/10/2012 19:00 | 17/10/2012 19:02 |       0 |       0 |
|         1 | 17/10/2012 19:02 | 17/10/2012 19:03 |       1 |       0 |
|         1 | 17/10/2012 19:03 | 17/10/2012 19:05 |       1 |       1 |
|         1 | 17/10/2012 19:05 | 17/10/2012 19:10 |       1 |       0 |
|         1 | 17/10/2012 19:10 | 17/10/2012 19:20 |       0 |       0 |
|         1 | 17/10/2012 19:20 | 17/10/2012 19:26 |       1 |       0 |
|         1 | 17/10/2012 19:26 | 17/10/2012 19:30 |       1 |       1 |
+-----------+------------------+------------------+---------+---------+

II:

+-----+------------------+------------------+--------+---------+----------+----------+
| PID |      START       |       END        | InHOME | TotTIME | FreeTIME | StudTIME |
+-----+------------------+------------------+--------+---------+----------+----------+
|   1 | 17/10/2012 19:00 | 17/10/2012 19:02 |      0 | 2min    | 2min     | 0min     |
|   1 | 17/10/2012 19:02 | 17/10/2012 19:10 |      1 | 8min    | 6min     | 2min     |
|   1 | 17/10/2012 19:10 | 17/10/2012 19:20 |      0 | 10min   | 10min    | 0min     |
|   1 | 17/10/2012 19:20 | 17/10/2012 19:26 |      1 | 6min    | 6min     | 0min     |
+-----+------------------+------------------+--------+---------+----------+----------+

解决这些问题的最佳解决方案是什么?

2 个答案:

答案 0 :(得分:0)

第一个可能看起来像这样。我只是不明白,为什么你在报告的最后一行中有STUDYING = 0(错误可能是?)

select
    T.PERSON_ID,
    min(T.[TIMESTAMP]) as START,
    CALC.[TIMESTAMP] as [END],
    T.IN_HOME, T.STUDYNG
from @Temp as T
    cross apply
    (
        select top 1 TT.*
        from @Temp as TT
        where 
            TT.PERSON_ID = T.PERSON_ID and TT.[TIMESTAMP] > T.[TIMESTAMP] and
            (TT.IN_HOME <> T.IN_HOME or TT.STUDYNG <> T.STUDYNG)
        order by TT.[TIMESTAMP] asc
    ) as CALC
group by 
    T.PERSON_ID,
    CALC.[TIMESTAMP],
    T.IN_HOME, T.STUDYNG
order by START

答案 1 :(得分:0)

如果您可以使用SQL 2012(如标题中所述),我建议您考虑使用LEAD/LAG函数。

当SQL Fiddle重新上线时,我会做一个很好的小例子。

这是第一部分:

;WITH DATA 
     AS (SELECT *, 
                CASE 
                  WHEN ID = 1 THEN 1 
                  ELSE 
                    CASE 
                      WHEN IN_HOME = Lag(IN_HOME, 1) 
                                       OVER ( 
                                         ORDER BY TIMESTAMP) 
                           AND STUDYNG = Lag(STUDYNG, 1) 
                                           OVER ( 
                                             ORDER BY TIMESTAMP) THEN 0 
                      ELSE 1 
                    END 
                END rn 
         FROM   STUDY), 
     PREPARED_DATA 
     AS (SELECT t1.ID, 
                t1.PERSON_ID, 
                t1.TIMESTAMP, 
                Sum(t2.RN) RN, 
                t1.IN_HOME, 
                t1.STUDYNG 
         FROM   DATA t1 
                INNER JOIN DATA t2 
                        ON t1.ID >= t2.ID 
         GROUP  BY t1.ID, 
                   t1.PERSON_ID, 
                   t1.TIMESTAMP, 
                   t1.IN_HOME, 
                   t1.STUDYNG), 
     SECOND 
     AS (SELECT PERSON_ID, 
                Max(TIMESTAMP) max_time, 
                Min(TIMESTAMP) min_time, 
                IN_HOME, 
                STUDYNG 
         FROM   PREPARED_DATA 
         GROUP  BY PERSON_ID, 
                   IN_HOME, 
                   STUDYNG, 
                   RN) 
SELECT PERSON_ID, 
       MAX_TIME, 
       Lead(MIN_TIME, 1) 
         OVER ( 
           ORDER BY MIN_TIME), 
       IN_HOME, 
       STUDYNG 
FROM   SECOND 
ORDER  BY MIN_TIME 

可以找到一个工作示例here 如果你喜欢这个想法,我也可以准备第二部分。请告诉我。