在SQL Server 2016中创建间隔

时间:2018-07-10 08:05:22

标签: sql sql-server datetime sql-server-2016 intervals

我有下表:

SystemDown               SystemUp
------------------------------------------------
NULL                     2018-07-05 15:02:11.903
NULL                     2018-07-05 15:02:17.903
NULL                     2018-07-05 15:02:23.903
NULL                     2018-07-05 15:02:29.907
NULL                     2018-07-05 15:02:35.907
NULL                     2018-07-05 15:02:41.903
NULL                     2018-07-05 15:02:05.903
2018-07-05 15:02:41.903  NULL
2018-07-05 15:04:05.907  NULL
NULL                     2018-07-05 15:06:40.433
NULL                     2018-07-05 15:07:10.430
NULL                     2018-07-05 15:07:40.430
NULL                     2018-07-05 15:08:10.430

我要创建此表:

 Status   StartDate                   EndDate
 -------------------------------------------------------------
 UP       2018-07-05 15:02:05.903     2018-07-05 15:02:41.903
 Down     2018-07-05 15:02:41.903     2018-07-05 15:04:05.907
 UP       2018-07-05 15:06:40.433     2018-07-05 15:08:10.430

其中间隔由每个间隔中的第一个和最后一个时间戳定义。

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

以下似乎有效:

;WITH CountCTE AS (
   SELECT SystemDown, SystemUp,
          ROW_NUMBER() OVER (ORDER BY COALESCE(SystemDown, SystemUp)) AS rn,
          COUNT(SystemUp) OVER (ORDER BY  SystemUp) AS countUp,
          COUNT(SystemDown) OVER (ORDER BY SystemDown) AS countDown
   FROM mytable
), GroupCTE AS (
   SELECT SystemDown, SystemUp,
          COALESCE(SystemDown, SystemUp) AS t,
          IIF(SystemUp IS NOT NULL, 'UP', 'DOWN') AS Status,
          rn - countUp AS grpUp,
          rn - countDown AS grpDown
   FROM CountCTE
)
SELECT Status,
       MIN(t) AS StartDate,
       MAX(t) AS EndDate
FROM GroupCTE
GROUP BY Status, 
         IIF(Status = 'UP', grpUp, grpDown)
ORDER BY StartDate

Demo here

如果您检查GroupCTE的中间结果,则可以深入了解其工作原理:

SystemDown              SystemUp                 Status grpUp   grpDown
------------------------------------------------------------------------
NULL                    2018-07-05 15:02:05.903  UP     0       1
NULL                    2018-07-05 15:02:11.903  UP     0       2
NULL                    2018-07-05 15:02:17.903  UP     0       3
NULL                    2018-07-05 15:02:23.903  UP     0       4
NULL                    2018-07-05 15:02:29.907  UP     0       5
NULL                    2018-07-05 15:02:35.907  UP     0       6
NULL                    2018-07-05 15:02:41.903  UP     0       7
NULL                    2018-07-05 15:06:40.433  UP     2       10
NULL                    2018-07-05 15:07:10.430  UP     2       11
NULL                    2018-07-05 15:07:40.430  UP     2       12
NULL                    2018-07-05 15:08:10.430  UP     2       13
2018-07-05 15:02:41.903 NULL                     DOWN   8       7
2018-07-05 15:04:05.907 NULL                     DOWN   9       7

答案 1 :(得分:1)

您可以使用ROW_NUMBER()来生成排名,然后将它们放在一起以将间隔进行分组(其余一致的记录是连续的,从而获得相同的组号)。

IF OBJECT_ID('tempdb..#YourTable') IS NOT NULL
    DROP TABLE #YourTable

CREATE TABLE #YourTable (
    SystemDown DATETIME,
    SystemUp DATETIME)

INSERT INTO #YourTable (
    SystemDown,
    SystemUp)
VALUES
    (NULL, '2018-07-05 15:02:05.903'),
    (NULL, '2018-07-05 15:02:11.903'),
    (NULL, '2018-07-05 15:02:17.903'),
    (NULL, '2018-07-05 15:02:23.903'),
    (NULL, '2018-07-05 15:02:29.907'),
    (NULL, '2018-07-05 15:02:35.907'),
    (NULL, '2018-07-05 15:02:41.903'),
    ('2018-07-05 15:02:41.903', NULL),
    ('2018-07-05 15:04:05.907', NULL),
    (NULL, '2018-07-05 15:06:40.433'),
    (NULL, '2018-07-05 15:07:10.430'),
    (NULL, '2018-07-05 15:07:40.430'),
    (NULL, '2018-07-05 15:08:10.430')

;WITH Rankings AS
(
    SELECT
        SystemDown = T.SystemDown,
        SystemUp = T.SystemUp,
        GeneralRanking = ROW_NUMBER() OVER (ORDER BY ISNULL(T.SystemDown, T.SystemUp) ASC),
        UpRanking = ROW_NUMBER() OVER (ORDER BY T.SystemUp ASC),
        DownRanking = ROW_NUMBER() OVER (ORDER BY T.SystemDown ASC)
    FROM
        #YourTable AS T
),
UpTimes AS
(
    SELECT
        Status = 'Up',
        StartDate = MIN(R.SystemUp),
        EndDate = MAX(R.SystemUp)
    FROM
        Rankings AS R
    WHERE
        R.SystemUp IS NOT NULL
    GROUP BY
        R.GeneralRanking - R.UpRanking
),
DownTimes AS
(
    SELECT
        Status = 'Down',
        StartDate = MIN(R.SystemDown),
        EndDate = MAX(R.SystemDown)
    FROM
        Rankings AS R
    WHERE
        R.SystemDown IS NOT NULL
    GROUP BY
        R.GeneralRanking - R.DownRanking
)
SELECT
    U.Status,
    U.StartDate,
    U.EndDate
FROM
    UpTimes AS U
UNION ALL
SELECT
    D.Status,
    D.StartDate,
    D.EndDate
FROM
    DownTimes AS D
ORDER BY
    StartDate ASC

结果:

Status  StartDate                   EndDate
Up      2018-07-05 15:02:05.903     2018-07-05 15:02:41.903
Down    2018-07-05 15:02:41.903     2018-07-05 15:04:05.907
Up      2018-07-05 15:06:40.433     2018-07-05 15:08:10.430