【问题标题】:How do I calculate the amount of time per hour that table meets condition in SQL如何计算表在 SQL 中满足条件的每小时时间量
【发布时间】:2021-05-21 17:32:56
【问题描述】:

抱歉,如果我没有给你正确的格式/打破礼仪,我通常会发布 python 问题,创建问题的虚拟示例很容易,但我的 SQL 技能还不足以做到这一点。非常感谢您的反馈。

我在 SQL 中有一个运行表,它监视运行的状态并记录运行和停止周期的开始和结束,如下所示。真实表从过去的某个日期开始运行,并将继续运行到未来,并且状态可以持续几秒、几分钟、几天、几周,尤其是停止。

Start End Status
2021-01-01 00:00:00.000 2021-01-01 00:30:00.000 Run
2021-01-01 00:30:00.000 2021-01-01 10:30:00.000 Stop
2021-01-01 10:30:00.000 2021-01-02 10:00:00.000 Run
2021-01-02 10:00:00.000 2021-01-02 17:00:00.000 Run
2021-01-02 17:00:00.000 2021-02-01 09:00:00.000 Run

我需要计算每小时的状态,每个小时开始的结果表如下所示(但直到当前小时) - 它会返回以分钟为单位的时间量(或秒)机器每小时处于每种状态。另外,我不是特别在意0,而是将它们放在示例中。

Hour Time in Status(mins) Status
2021-01-01 00:00:00.000 30 Run
2021-01-01 00:00:00.000 30 Stop
2021-01-01 01:00:00.000 0 Run
2021-01-01 01:00:00.000 60 Stop
...
2021-02-01 08:00:00.000 60 Run
2021-02-01 08:00:00.000 0 Stop

我可以相对容易地计算当前的小时状态(即我可以返回 2020-01-01 00:00:00.000 运行了 30 分钟,停止了 30 分钟)但是当我尝试添加剩余的时间时,我的知识让我失望了到下一个小时的时间。

我正在 SQL Server 2017 上开发 SQL Server Management Studio。

【问题讨论】:

  • 你想从什么时候开始?表格的开头?
  • 那你怎么办?
  • 本意是从表格的开头开始,但如果更容易,我们可以从 01-01-2021 开始(不是表格的真正开始,而是我用作示例的)。错过时间是什么意思?不应该有任何缺失的时间,只有机器处于停止模式很多小时的时间段。
  • 缺少小时数意味着它们根本不存在于表中。而且我在我的回答中假设您希望 0 用于该状态没有任何内容的任何时间,即您仍然需要该小时的一行和 0 的标题,因此我们需要一个 Hours 表。如果这些都不正确,我们可以删除 Hours 表。
  • 啊,我明白了,是的,你是对的。欣赏解决方案;明天会尝试,可能会带着一些问题回来。感谢您抽出宝贵时间。

标签: sql-server


【解决方案1】:

为此,我们可以使用 Hour 表并将您的表左连接到它,我们可以使用计数表动态生成它。我在这里使用了 Itzik Ben-Gan 的标准:

WITH
    L0 AS ( SELECT 1 AS c 
            FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),
                        (1),(1),(1),(1),(1),(1),(1),(1)) AS D(c) ),
    L1 AS ( SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B ),
    L2 AS ( SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B ),
    L3 AS ( SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B ),
    Nums AS ( SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
              FROM L3 ),
  Hours AS (
    SELECT TOP(DATEDIFF(hour, @startDate, GETDATE()) + 1)
       DATEADD(hour, rownum - 1, @startDate) AS startHour,
       DATEADD(hour, rownum, @startDate) AS endHour
    FROM Nums
    ORDER BY rownum
  )

SELECT
    h.hour,
    v.Status,
    SUM(DATEDIFF(mi,
        CASE WHEN h.hour > t.Start THEN h.hour ELSE t.Start END,
        CASE WHEN h.hour < t.[End] THEN h.hour ELSE t.[End] END
    ))
FROM Hours h
CROSS JOIN (VALUES ('Run'), ('Stop') ) v(Status)
LEFT JOIN myTable t
    ON t.Start < h.endHour AND t.[End] > h.startHour
    AND t.Status = v.Status
GROUP BY h.startHour, v.Status;

DATEDIFF(min 每行只会给你整分钟,所以如果你想计算分数,请使用DATEDIFF(ms 并除以60000.0

【讨论】:

  • h.hour 在这里意味着什么?看起来你没有定义它。
  • 对不起是h.startHour
  • 我不认为这按预期工作。对于在 myTable 中有时间的行,它们都有一个负数(并且相当高 - 远高于 60 分钟......),并且表中不存在的时间在运行和停止的列中都有 0,甚至虽然停止包含它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-14
  • 2018-04-25
  • 2021-11-28
  • 1970-01-01
  • 1970-01-01
  • 2019-05-10
相关资源
最近更新 更多