Sql server 如何计算SQL Server中一列的两行之间的持续时间?

Sql server 如何计算SQL Server中一列的两行之间的持续时间?,sql-server,Sql Server,数据库中有这样的数据 ID Server DownTime ServerStatus --- ----------------------- ------------ 1 2012-03-30 00:00:00.000 1 2 2012-03-30 00:30:00.000 0 3 2012-03-30 01:00:00.000 0 4 2012-03-30 01:30:00.000 0 5 2012-03-30 02:00:00.000 1

数据库中有这样的数据

ID  Server DownTime          ServerStatus
--- -----------------------  ------------
1   2012-03-30 00:00:00.000  1
2   2012-03-30 00:30:00.000  0
3   2012-03-30 01:00:00.000  0
4   2012-03-30 01:30:00.000  0
5   2012-03-30 02:00:00.000  1
6   2012-03-30 02:30:00.000  1
7   2012-03-30 03:00:00.000  0
8   2012-03-30 03:30:00.000  1
我需要一个查询或存储过程,将给我作为输出

Start Time    EndTime       TotalDownTimeinMinutes
------------  ------------  ----------------------
3/30/12 0:30  3/30/12 2:00  90
3/30/12 3:00  3/30/12 3:30  30
您可以使用此DDL测试上述查询

create table Tbl
(
ID int,
ServerDownTime datetime,
ServerStatus bit
)
insert Tbl select
1   ,'2012-03-30 00:00:00.000',  1 union all select
2   ,'2012-03-30 00:30:00.000',  0 union all select
3   ,'2012-03-30 01:00:00.000',  0 union all select
4   ,'2012-03-30 01:30:00.000',  0 union all select
5   ,'2012-03-30 02:00:00.000',  1 union all select
6   ,'2012-03-30 02:30:00.000',  1 union all select
7   ,'2012-03-30 03:00:00.000',  0 union all select
8   ,'2012-03-30 03:30:00.000',  1
或者,如果您在web上,但离SQL Server不远,则以下是此解决方案的基础:

基本思想是将行分组,从ServerStatus=0行开始,以ServerStatus=1行结束。例如,如果运行此查询,您将看到停机组(列GroupID)::


请将列的格式设置为实际列。。如果您还包括列类型,那就太棒了。谢谢您的更新。这对我真的很有帮助。我可以知道GROUP BY上面X的含义吗。@Linnet-FROM子句中的每个表或行源都必须有一个名称。引用表时,名称(默认情况下)为表的名称。使用子查询时,必须提供别名(在本例中为
X
)。然而,在本例中选择的名称并不重要-它可以是任何东西。@Richard aka cyberkiwi-非常感谢。
create table Tbl
(
ID int,
ServerDownTime datetime,
ServerStatus bit
)
insert Tbl select
1   ,'2012-03-30 00:00:00.000',  1 union all select
2   ,'2012-03-30 00:30:00.000',  0 union all select
3   ,'2012-03-30 01:00:00.000',  0 union all select
4   ,'2012-03-30 01:30:00.000',  0 union all select
5   ,'2012-03-30 02:00:00.000',  1 union all select
6   ,'2012-03-30 02:30:00.000',  1 union all select
7   ,'2012-03-30 03:00:00.000',  0 union all select
8   ,'2012-03-30 03:30:00.000',  1
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
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