我在MS SQL Server中有一个类似于下面的表。
id | Timestamp | active
-----+-----------+--------
1 | 1:00 | 1
1 | 2:00 | 1
1 | 3:00 | 1
1 | 4:00 | 0
1 | 5:00 | 0
1 | 6:00 | 1
1 | 7:00 | 0
1 | 8:00 | 0
1 | 9:00 | 0
1 | 10:00 | 1
1 | 11:00 | 1
1 | 12:00 | 0
1 | 13:00 | 1
2 | 2:00 | 1
2 | 3:00 | 1
2 | 4:00 | 0
2 | 5:00 | 0
3 | 8:00 | 0
3 | 9:00 | 0
4 | 1:00 | 1
4 | 2:00 | 1
5 | 16:00 | 0
我想要做的是找出每个ID处于非活动状态(活动= 0)多长时间。我尝试做的是在active = 0时按id分组,并在最小和最大时间进行一次约会。但这会给我一个id 1的结果,表示它已经离线8小时(12:00 - 4:00)@ 12:00。当我真正想要的是一个查询,它将给我以下结果集。
id | approx. offline in hours | at time
---+--------------------------+-----------
1 | 1 | 5:00
1 | 2 | 9:00
1 | 0 | 12:00
2 | 1 | 5:00
3 | 0 | 9:00
5 | 0 | 16:00
我最初尝试的错误查询是
SELECT id as [Inactive],
DATEDIFF(hour, MIN(Timestamp), MAX(Timestamp)) as [approx. offline in hours],
MAX(Timestamp) as [at time]
FROM table
WHERE active = 0
GROUP BY [Inactive]
但该查询的问题在于它会跳过两者之间的活动时间。我一直在查看THIS使用PARTITION询问和回答的问题,但看起来这个问题已经足够不同了,而且答案太具体了,我无法回答这个问题。理解它。
感谢任何帮助。
答案 0 :(得分:3)
在任何数据库中使用的一种方法是使用相关子查询。我们的想法是为每个连续的活动值字符串分配一个组名。特定的组名是下次更改值的时间。
select id, active, min(TimeStamp), max(TimeStamp)
from (select t.*,
(select min(timeStamp) from t t2 where t2.id = t.id and t2.timeStamp > t.timeStamp and t2.active <> t.active
) groupName
from t
) t
group by id, groupName, active
有一点需要注意,如何将转换时间戳转换为持续时间取决于数据库。由于您没有指定数据库,我将允许您添加该逻辑。
此外,如果给定id的最后一条记录处于非活动状态,则groupname为NULL。那不是问题。