SQL在较大的时间跨度内计算多个时间差

问题描述 投票:0回答:4

我有一个sql后端,有一个跟踪两个日期列的表。这两列称为OnTime和OffTime。列的格式为小日期时间。该表由一个带有VB形式应用程序的arduino微控制器填充,当检测到电压时,该应用程序将在OnTime列中插入日期,并在电压被移除时填充OffTime日期。我需要编写一个sql查询,它可以收集每个开关时间戳之间检测到的总时间电压。查询看起来应该是这样的

SELECT (get times) FROM tableA WHERE OnTime >= @sometime AND OffTime <= @Sometime.

这将允许我运行关于检测到电压的总分钟的报告。我熟悉使用Datediff()函数获得时间,但我不确定以这种方式汇总多个datediff()

样本数据:

| ID | OnTime           | OffTime          |
|----|------------------|------------------|
| 1  | 2017-01-01 09:36 | null             |
| 2  | null             | 2017-01-01 10:36 |
| 3  | 2017-01-07 05:36 | null             |
| 4  | null             | 2017-01-07 6:36 |

其中,正常运行时间和停机时间是列。

期望的结果是总时间是120分钟

sql sql-server date datetime sql-server-2017
4个回答
2
投票

您可以使用组合行的老式方法:

WITH testdata (ID, OnTime, OffTime) AS (
    SELECT 1, '2017-01-01 09:36', null UNION
    SELECT 2, null, '2017-01-01 10:36' UNION
    SELECT 3, '2017-01-07 05:36', null UNION
    SELECT 4, null, '2017-01-07 6:36'
), on_off_time AS (
    SELECT a.ID, a.OnTime, MIN(b.OffTime) AS OffTime
    FROM testdata a
    INNER JOIN testdata b ON b.OffTime > a.OnTime
    GROUP BY a.ID, a.OnTime
)
SELECT SUM(DATEDIFF(MINUTE, OnTime, OffTime))
FROM on_off_time

或者使用LAG函数(SQL Server 2012或更高版本):

WITH testdata (ID, OnTime, OffTime) AS (
    SELECT 1, '2017-01-01 09:36', null UNION
    SELECT 2, null, '2017-01-01 10:36' UNION
    SELECT 3, '2017-01-07 05:36', null UNION
    SELECT 4, null, '2017-01-07 6:36'
), on_off_time AS (
    SELECT ID, LAG(OnTime, 1, NULL) OVER (ORDER BY COALESCE(OnTime, OffTime)) AS OnTime, OffTime
    FROM testdata
)
SELECT SUM(DATEDIFF(MINUTE, OnTime, OffTime))
FROM on_off_time
WHERE OffTime IS NOT NULL

1
投票

考虑到表

ID | OnTime             | OffTime
---|--------------------|--------------
  1|2018-02-12 08:00:00 |null
  2|null                |2018-02-12 09:00:00
  3|2018-02-13 07:00:00 |null
  4|null                |2018-02-13 09:00:00

您可以执行以下操作:

WITH Ons AS
(
 SELECT ID,
        ID + 1 AS IDPlusOne,
        OnTime
 FROM Dates
 WHERE NOT OnTime IS NULL 
)
,

Offs AS
(
 SELECT ID,
        OffTime
 FROM Dates
 WHERE NOT OffTime IS NULL
)

SELECT Ons.ID, 
       Offs.ID, 
       DateDiff(MINUTE, Ons.OnTime, Offs.OffTime) as DiffInMinutes 
FROM Ons INNER JOIN Offs ON Ons.IDPlusOne = Offs.ID

结果是

ID | ID | DiffInMinutes
---|----|---------------
  1|   2|60
  3|   4|120

然而,您的设计相当不幸,因为它要求记录严格按顺序排列。我强烈建议在同一记录中保存两个日期时间


0
投票

如果您的条目始终与其ID一致,则可以使用此简单方法获取每个数据点之间的时间:

SELECT ID,DATEDIFF(MINUTE, Ontime, (SELECT Offtime FROM yourtable t2 where t2.ID = t.ID+1)) AS 'Minutes on, per period'
FROM yourtable t
WHERE Ontime is not null;

您可以根据需要进行扩展,例如通过这样的总结

 SELECT SUM(Minutes) AS 'Total minutes on, all periods'
    FROM (
      SELECT ID,DATEDIFF(MINUTE, Ontime, (SELECT Offtime FROM yourtable t2 where t2.ID = t.ID+1)) AS 'Minutes'
      FROM yourtable t
      WHERE Ontime is not null
    ) AS Subtable

如果你想尝试这个例子,我在这里做了一个小提琴:http://sqlfiddle.com/#!6/9db41/18


0
投票

以下代码对您有所帮助,

;WITH tblDateDifference AS
(
    SELECT ROW_NUMBER() OVER(ORDER BY ID) AS RowNumber, OnTime,OffTime
    FROM tableA
)

SELECT sum(DATEDIFF(MINUTE,cur.OnTime,nxt.OffTime)) AS TotalMinute
FROM tblDateDifference cur,tblDateDifference nxt
WHERE nxt.RowNumber = cur.RowNumber + 1

点击这里:http://sqlfiddle.com/#!6/1c4bd/3

© www.soinside.com 2019 - 2024. All rights reserved.