计算值大于 x 的时间(以分钟为单位)

Calculate the time in minutes that a value has been greater than x

我希望能够计算温度列超过特定温度的总时间(以分钟为单位)。例如,我想知道温度在 16 度以上的时间是多少分钟。

如果 12:28 的读数是 1612:30 的读数是 17,我们说的是从 12:2812:30,值为 17.

此外,如果第一个或唯一一个读数高于 x (17),则这将是两分钟,因为设备启动后需要 x 分钟(在本例中为 2 分钟)才能获取第一个读数。


  SerialNumber, CombinDateTime, Temperature
  1000649496, 2018-12-05 10:56:52,    16.6
  1000649496, 2018-12-05 10:58:52,    17.3
  1000649496, 2018-12-05 11:00:52,    16.8
  1000649496, 2018-12-05 11:02:52,    16.6
  1000649496, 2018-12-05 11:04:52,    16.4
  1000649496, 2018-12-05 11:06:52,    16.3
  1000649496, 2018-12-05 11:08:52,    16.3
  1000649496, 2018-12-05 11:10:52,    16.2
  1000649496, 2018-12-05 11:12:52,    16.2
  1000649496, 2018-12-05 11:14:52,    16.2
  1000649496, 2018-12-05 11:16:52,    16.2
  1000649496, 2018-12-05 11:18:52,    16.2
  1000649496, 2018-12-05 11:20:52,    16.1
  1000649496, 2018-12-05 11:22:52,    16.1
  1000649496, 2018-12-05 11:24:52,    16.1
  1000649496, 2018-12-05 11:26:52,    16
  1000649496, 2018-12-05 11:28:52,    16
  1000649496, 2018-12-05 11:30:52,    16
  1000649496, 2018-12-05 11:32:52,    16
  1000649496, 2018-12-05 11:34:52,    16.1
  1000649496, 2018-12-05 11:36:52,    16.1
  1000649496, 2018-12-05 11:38:52,    16.1
  1000649496, 2018-12-05 11:40:52,    16.1
  1000649496, 2018-12-05 11:42:52,    16.1
  1000649496, 2018-12-05 11:44:52,    16.1
  1000649496, 2018-12-05 11:46:52,    16.1
  1000649496, 2018-12-05 11:48:52,    16
  1000649496, 2018-12-05 11:50:52,    16
  1000649496, 2018-12-05 11:52:52,    16
  1000649496, 2018-12-05 11:54:52,    16
  1000649496, 2018-12-05 11:56:52,    16
  1000649496, 2018-12-05 11:58:52,    16
  1000649496, 2018-12-05 12:00:52,    16.1
  1000649496, 2018-12-05 12:02:52,    16.1
  1000649496, 2018-12-05 12:04:52,    16.1
  1000649496, 2018-12-05 12:06:52,    16.1
  1000649496, 2018-12-05 12:08:52,    16
  1000649496, 2018-12-05 12:10:52,    16
  1000649496, 2018-12-05 12:12:52,    16
  1000649496, 2018-12-05 12:14:52,    16
  1000649496, 2018-12-05 12:16:52,    16
  1000649496, 2018-12-05 12:18:52,    16
  1000649496, 2018-12-05 12:20:52,    16
  1000649496, 2018-12-05 12:22:52,    16
  1000649496, 2018-12-05 12:24:52,    16
  1000649496, 2018-12-05 12:26:52,    16
  1000649496, 2018-12-05 12:28:52,    16
  1000649496, 2018-12-05 12:30:52,    16
  1000649496, 2018-12-08 08:08:52,    15.1
  1000649496, 2018-12-05 12:32:52,    16
  1000649496, 2018-12-05 12:34:52,    16
  1000649496, 2018-12-05 12:36:52,    16
  1000649496, 2018-12-05 12:38:52,    16

到目前为止我的查询非常基础:

    SELECT SerialNumber, CombineDateTime, Temperature 
    FROM RawData
    WHERE Temperature > 16

我想到的原则是我 select 数据集和 order by date 并遍历每一行,直到找到超过 16 的值。然后我获取日期,然后遍历记录,直到找到 <= 16 的值,然后获取该日期和时间以及 datediff() minutes 中的期间。

我知道你不应该遍历 SQL 条记录,所以我正在考虑使用 CTE,但我不太确定该怎么做。

我的预期结果例如是:

    SerialNumber, MinutesOver 
    1000649496, 1186

TIA

您希望对日期部分的分钟求和,然后按序列号分组

SELECT SUM(DATEPART(minute, [CombinDateTime])) AS total_call_time , [SerialNumber] FROM [dbo].[Table_1] WHERE [Temperature]>16 GROUP BY [SerialNumber];

这看起来像是一个间隙和孤岛问题(连续> 16个温度和<= 16个温度需要分组在一起),一种解决方案如下:

DECLARE @threshold DECIMAL(18, 2) = 16;
WITH cte1 AS (
    SELECT *, CASE 
           -- first row itself is greater than threshold
           WHEN Temperature  >  @threshold  AND  LAG(Temperature)  OVER (PARTITION BY SerialNumber ORDER BY CombinDateTime) IS NULL      THEN 1
           -- next row is greater than threshold
           WHEN Temperature <=  @threshold  AND LEAD(Temperature)  OVER (PARTITION BY SerialNumber ORDER BY CombinDateTime) > @threshold THEN 1
           -- prev row is greater than threshold
           WHEN Temperature <=  @threshold  AND  LAG(Temperature)  OVER (PARTITION BY SerialNumber ORDER BY CombinDateTime) > @threshold THEN 1
    END AS chg
    FROM @t
), cte2 AS (
    SELECT *, SUM(chg) OVER (PARTITION BY SerialNumber ORDER BY CombinDateTime) AS grp
    FROM cte1
)
SELECT SerialNumber
     , MIN(CombinDateTime) AS StartDateTime
     , MAX(CombinDateTime) AS EndDateTime
     , DATEDIFF(SECOND, MIN(CombinDateTime), MAX(CombinDateTime)) / 60.0 AS Total
FROM cte2
GROUP BY SerialNumber, grp
HAVING MAX(Temperature) > @threshold

结果:

SerialNumber  StartDateTime        EndDateTime          Total
1000649496    2018-12-05 10:56:52  2018-12-05 11:24:52  28.000000
1000649496    2018-12-05 11:32:52  2018-12-05 11:46:52  14.000000
1000649496    2018-12-05 11:58:52  2018-12-05 12:06:52  8.000000

具有 LAG 和滚动 SUM window 功能的解决方案:

DECLARE @ThresholdTemperature DECIMAL(3, 1) = 16

;WITH BreakMarker AS
(
    -- Determine if the temperature is above or below the threshold
    SELECT
        M.*,
        LimitMarker = CASE WHEN M.Temperature > @ThresholdTemperature THEN 0 ELSE 1 END
    FROM
        #Measures AS M
),
LaggedChange AS
(
    -- Determine at which point in time the temperature moves between the threshold
    SELECT
        B.*,
        TempChange = CASE WHEN B.LimitMarker = LAG(B.LimitMarker, 1, 0) OVER (
            PARTITION BY 
                B.SerialNumber 
            ORDER BY 
                B.CombinDateTime ASC) THEN 0 ELSE 1 END
    FROM
        BreakMarker AS B
),
BreakGroups AS
(
    -- Generate a group ID value to calculate MAX and MIN
    SELECT
        L.*,
        BreakGroup = SUM(TempChange) OVER (PARTITION BY L.SerialNumber ORDER BY L.CombinDateTime ASC)
    FROM
        LaggedChange AS L
)
SELECT
    B.SerialNumber,
    MinCombinDateTime = MIN(B.CombinDateTime),
    MaxCombinDateTime = MAX(B.CombinDateTime),
    MinutesOver = DATEDIFF(MINUTE, MIN(B.CombinDateTime), MAX(B.CombinDateTime))
FROM
    BreakGroups AS B
GROUP BY
    B.SerialNumber,
    B.BreakGroup
HAVING
    MIN(B.Temperature) > @ThresholdTemperature

结果:

SerialNumber    MinCombinDateTime           MaxCombinDateTime           MinutesOver
1000649496      2018-12-05 10:56:52.000     2018-12-05 11:24:52.000     28
1000649496      2018-12-05 11:34:52.000     2018-12-05 11:46:52.000     12
1000649496      2018-12-05 12:00:52.000     2018-12-05 12:06:52.000     6

您可以在此处查看 CTE 的临时结果,这样更容易理解分步逻辑:

SerialNumber    CombinDateTime              Temperature LimitMarker TempChange  BreakGroup
1000649496      2018-12-05 10:56:52.000     16.6        0           0           0
1000649496      2018-12-05 10:58:52.000     17.3        0           0           0
1000649496      2018-12-05 11:00:52.000     16.8        0           0           0
1000649496      2018-12-05 11:02:52.000     16.6        0           0           0
1000649496      2018-12-05 11:04:52.000     16.4        0           0           0
1000649496      2018-12-05 11:06:52.000     16.3        0           0           0
1000649496      2018-12-05 11:08:52.000     16.3        0           0           0
1000649496      2018-12-05 11:10:52.000     16.2        0           0           0
1000649496      2018-12-05 11:12:52.000     16.2        0           0           0
1000649496      2018-12-05 11:14:52.000     16.2        0           0           0
1000649496      2018-12-05 11:16:52.000     16.2        0           0           0
1000649496      2018-12-05 11:18:52.000     16.2        0           0           0
1000649496      2018-12-05 11:20:52.000     16.1        0           0           0
1000649496      2018-12-05 11:22:52.000     16.1        0           0           0
1000649496      2018-12-05 11:24:52.000     16.1        0           0           0
1000649496      2018-12-05 11:26:52.000     16.0        1           1           1
1000649496      2018-12-05 11:28:52.000     16.0        1           0           1
1000649496      2018-12-05 11:30:52.000     16.0        1           0           1
1000649496      2018-12-05 11:32:52.000     16.0        1           0           1
1000649496      2018-12-05 11:34:52.000     16.1        0           1           2
1000649496      2018-12-05 11:36:52.000     16.1        0           0           2
1000649496      2018-12-05 11:38:52.000     16.1        0           0           2
1000649496      2018-12-05 11:40:52.000     16.1        0           0           2
1000649496      2018-12-05 11:42:52.000     16.1        0           0           2
1000649496      2018-12-05 11:44:52.000     16.1        0           0           2
1000649496      2018-12-05 11:46:52.000     16.1        0           0           2
1000649496      2018-12-05 11:48:52.000     16.0        1           1           3
1000649496      2018-12-05 11:50:52.000     16.0        1           0           3
1000649496      2018-12-05 11:52:52.000     16.0        1           0           3
1000649496      2018-12-05 11:54:52.000     16.0        1           0           3
1000649496      2018-12-05 11:56:52.000     16.0        1           0           3
1000649496      2018-12-05 11:58:52.000     16.0        1           0           3
1000649496      2018-12-05 12:00:52.000     16.1        0           1           4
1000649496      2018-12-05 12:02:52.000     16.1        0           0           4
1000649496      2018-12-05 12:04:52.000     16.1        0           0           4
1000649496      2018-12-05 12:06:52.000     16.1        0           0           4
1000649496      2018-12-05 12:08:52.000     16.0        1           1           5
1000649496      2018-12-05 12:10:52.000     16.0        1           0           5
1000649496      2018-12-05 12:12:52.000     16.0        1           0           5
1000649496      2018-12-05 12:14:52.000     16.0        1           0           5
1000649496      2018-12-05 12:16:52.000     16.0        1           0           5
1000649496      2018-12-05 12:18:52.000     16.0        1           0           5
1000649496      2018-12-05 12:20:52.000     16.0        1           0           5
1000649496      2018-12-05 12:22:52.000     16.0        1           0           5
1000649496      2018-12-05 12:24:52.000     16.0        1           0           5
1000649496      2018-12-05 12:26:52.000     16.0        1           0           5
1000649496      2018-12-05 12:28:52.000     16.0        1           0           5
1000649496      2018-12-05 12:30:52.000     16.0        1           0           5
1000649496      2018-12-05 12:32:52.000     16.0        1           0           5
1000649496      2018-12-05 12:34:52.000     16.0        1           0           5
1000649496      2018-12-05 12:36:52.000     16.0        1           0           5
1000649496      2018-12-05 12:38:52.000     16.0        1           0           5
1000649496      2018-12-08 08:08:52.000     15.1        1           0           5

您需要为每一行分配一个组。该组可以分配为在每行上或之后超过每行的值的数量。这将包括组中的 "closing" 行。

因此组分配为:

SELECT rd.*,
       SUM(CASE WHEN Temperature <= 16 THEN 1 ELSE 0 END) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime DESC) as grp
FROM RawData rd;

然后就可以使用聚合和过滤了。所以,这个returns你想要的时间跨度:

SELECT SerialNumber,
       MIN(CombineDateTime), MAX(CombineDateTime)
FROM (SELECT rd.*,
             SUM(CASE WHEN Temperature <= 16 THEN 1 ELSE 0 END) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime DESC) as grp
      FROM RawData rd
     ) rd
WHERE Temperature > 16
GROUP BY SerialNumber, grp;

最后,您可以计算总分钟数:

SELECT SUM(DATEDIFF(minute, min_cdt, max_cdt)
FROM (SELECT SerialNumber,
             MIN(CombineDateTime) as min_cdt,
             MAX(CombineDateTime) as max_cdt
      FROM (SELECT rd.*,
                   SUM(CASE WHEN Temperature <= 16 THEN 1 ELSE 0 END) OVER (PARTITION BY SerialNumber ORDER BY CombineDateTime DESC) as grp
            FROM RawData rd
           ) rd
      WHERE Temperature > 16
      GROUP BY SerialNumber, grp
     ) s;