使用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 |
+-----+------------------+------------------+--------+---------+----------+----------+
解决这些问题的最佳解决方案是什么?
答案 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 如果你喜欢这个想法,我也可以准备第二部分。请告诉我。