此解决方案基于递归 CTE:
DECLARE @MyTable TABLE (
ID INT PRIMARY KEY,
ServerDownTime DATETIME NOT NULL,
UNIQUE (ServerDownTime),
ServerStatus BIT NOT NULL
);
INSERT @MyTable (ID, ServerDownTime, ServerStatus)
SELECT 1,'2012-03-30T00:00:00',1 UNION ALL
SELECT 2,'2012-03-30T00:30:00',0 UNION ALL
SELECT 3,'2012-03-30T01:00:00',0 UNION ALL
SELECT 4,'2012-03-30T01:30:00',0 UNION ALL
SELECT 5,'2012-03-30T02:00:00',1 UNION ALL
SELECT 6,'2012-03-30T02:30:00',1 UNION ALL
SELECT 7,'2012-03-30T03:00:00',0 UNION ALL
SELECT 8,'2012-03-30T03:30:00',1;
WITH Base
AS
(
SELECT *, ROW_NUMBER() OVER(ORDER BY t.ServerDownTime) AS RowNum
FROM @MyTable t
), DownTimeGrouping
AS
(
SELECT crt.RowNum,
crt.ID,
crt.ServerDownTime,
crt.ServerStatus,
CASE WHEN crt.ServerStatus=0 THEN 1 END AS GroupID,
CASE WHEN crt.ServerStatus=0 THEN 1 ELSE 0 END AS LastGroupID
FROM Base crt
WHERE crt.RowNum=1
UNION ALL
SELECT crt.RowNum,
crt.ID,
crt.ServerDownTime,
crt.ServerStatus,
CASE
WHEN prev.ServerStatus=0 AND crt.ServerStatus IN(0,1) THEN prev.GroupID
WHEN prev.ServerStatus=1 AND crt.ServerStatus=0 THEN prev.LastGroupID+1
END AS GroupID,
CASE
WHEN prev.ServerStatus=0 AND crt.ServerStatus IN(0,1) THEN prev.GroupID
WHEN prev.ServerStatus=1 AND crt.ServerStatus=0 THEN prev.LastGroupID+1
WHEN prev.ServerStatus=1 AND crt.ServerStatus=1 THEN prev.GroupID
END AS LastGroupID
FROM Base crt
INNER JOIN DownTimeGrouping prev ON crt.RowNum=prev.RowNum+1
)
SELECT *, DATEDIFF(MINUTE,x.StartTime,x.EndTime) AS MinutesDiff
FROM (
SELECT t.GroupID, MIN(t.ServerDownTime) AS StartTime, MAX(t.ServerDownTime) AS EndTime
FROM DownTimeGrouping t
WHERE t.GroupID IS NOT NULL
GROUP BY t.GroupID
) x
基本思想是以 ServerStatus=0 行开始并以 ServerStatus=1 行结束的行进行分组。例如,如果您运行此查询,您将看到停机组(列 GroupID):
WITH Base
AS
(...), DownTimeGrouping
AS
(...)
SELECT *
FROM DownTimeGrouping g
ORDER BY g.RowNum
RowNum ID ServerDownTime ServerStatus GroupID LastGroupID
-------------------- ----------- ----------------------- ------------ ----------- -----------
1 1 2012-03-30 00:00:00.000 1 NULL 0
2 2 2012-03-30 00:30:00.000 0 1 1
3 3 2012-03-30 01:00:00.000 0 1 1
4 4 2012-03-30 01:30:00.000 0 1 1
5 5 2012-03-30 02:00:00.000 1 1 1
6 6 2012-03-30 02:30:00.000 1 NULL 1
7 7 2012-03-30 03:00:00.000 0 2 2
8 8 2012-03-30 03:30:00.000 1 2 2