【问题标题】:SQL Server : counting time between two values in two columnsSQL Server:计算两列中两个值之间的时间
【发布时间】:2020-06-30 21:00:42
【问题描述】:

我是 SQL Server 的新手(到目前为止 3 天的经验),我不知道如何在 excel 之外完成此操作,如果这很难解释,请见谅。

底部的表格示例:

我有一个表,其中包含每分钟的时间戳、零件计数器和错误代码。 我目前正在将零件计数合并为 15 分钟范围和该范围的总数,如下所示:

SELECT
    DATEADD(MINUTE, (DATEDIFF(MINUTE, '20000101', DateTime) / 15) * 15, '20000101') as Date_Time,
    MAX(Part_Count) - MIN(Part_Count) AS PartsMade
FROM 
    [SMP].[dbo].[33_TestImport]
WHERE
    [DateTime] >= DATEADD(HOUR, DATEDIFF(HOUR, 0, GETDATE()) - 24, 0)
GROUP BY
    DATEADD(MINUTE, (DATEDIFF(MINUTE, '20000101', DateTime) / 15) * 15, '20000101')

现在我正在尝试添加,再添加一行(暂时)。

PV_alarm 将变成一个数字,此时我想计算时间直到 part_count 增加,pv_alarm 可能会在它第一次触发和 part_count 再次增加之间发生多次变化。

所以:

  • PV_alarm 自然为零
  • PV_alarm 变为非零
  • PV_alarm 多次更改,最终将为零
  • 零件计数递增

为了更清楚:表格

DateTime              Part_Count    Alarm_Light PV_Alarm    Runtime_M
-----------------------------------------------------------------------
2020-03-18 20:16:06.040 340946  0   0   127076
2020-03-18 20:17:06.040 340953  0   0   127077
2020-03-18 20:18:06.040 340960  0   0   127078
2020-03-18 20:19:06.040 340967  0   0   127079
2020-03-18 20:20:06.040 340973  0   0   127080
2020-03-18 20:21:06.040 340978  1   8   127081   <--- timer would start here
2020-03-18 20:22:06.040 340978  1   8   127081
2020-03-18 20:23:06.040 340978  1   8   127081
2020-03-18 20:24:06.040 340978  1   8   127081
2020-03-18 20:25:06.040 340978  1   8   127081
2020-03-18 20:26:06.040 340978  1   8   127081
2020-03-18 20:27:06.040 340978  1   8   127081
2020-03-18 20:28:06.040 340978  1   8   127081
2020-03-18 20:29:06.040 340978  1   8   127081
2020-03-18 20:30:06.040 340978  1   8   127081
2020-03-18 20:31:06.040 340978  1   8   127081
2020-03-18 20:32:06.040 340978  1   8   127081
2020-03-18 20:33:06.040 340978  1   8   127081
2020-03-18 20:34:06.040 340978  1   8   127081
2020-03-18 20:35:06.040 340978  1   8   127081
2020-03-18 20:36:06.040 340978  1   8   127081
2020-03-18 20:37:06.040 340978  1   8   127081
2020-03-18 20:38:06.040 340978  1   8   127081
2020-03-18 20:39:06.040 340978  1   8   127081
2020-03-18 20:40:06.040 340978  1   8   127081
2020-03-18 20:41:06.040 340978  1   8   127081
2020-03-18 20:42:06.040 340978  1   8   127081
2020-03-18 20:43:06.040 340978  1   8   127081
2020-03-18 20:44:06.040 340978  1   8   127081
2020-03-18 20:45:06.040 340978  1   8   127081
2020-03-18 20:46:06.040 340978  1   8   127081
2020-03-18 20:47:06.040 340978  1   8   127081
2020-03-18 20:48:06.040 340978  1   8   127081
2020-03-18 20:49:06.040 340978  1   8   127081
2020-03-18 20:50:06.040 340978  1   8   127081
2020-03-18 20:51:06.040 340978  1   8   127081
2020-03-18 20:52:06.040 340978  1   8   127081
2020-03-18 20:53:06.040 340978  1   8   127081
2020-03-18 20:54:06.040 340978  1   8   127081
2020-03-18 20:55:06.040 340978  1   8   127081
2020-03-18 20:56:06.040 340978  1   8   127081
2020-03-18 20:57:06.040 340978  1   8   127081
2020-03-18 20:58:06.040 340978  1   8   127081
2020-03-18 20:59:06.040 340978  1   8   127081
2020-03-18 21:00:06.040 340978  1   8   127081
2020-03-18 21:01:06.040 340978  1   8   127081
2020-03-18 21:02:06.040 340978  1   8   127081
2020-03-18 21:03:06.040 340978  1   8   127081
2020-03-18 21:04:06.040 340978  1   8   127081
2020-03-18 21:05:06.040 340978  1   8   127081
2020-03-18 21:06:06.040 340978  1   8   127081
2020-03-18 21:07:06.040 340978  1   8   127081
2020-03-18 21:08:06.040 340978  1   8   127081
2020-03-18 21:09:06.040 340978  1   8   127081
2020-03-18 21:10:06.040 340978  1   8   127081
2020-03-18 21:11:06.040 340978  1   8   127081
2020-03-18 21:12:06.040 340978  0   0   127081
2020-03-18 21:13:06.040 340978  0   0   127081
2020-03-18 21:14:06.040 340978  0   0   127081
2020-03-18 21:15:06.040 340978  0   0   127081
2020-03-18 21:16:06.040 340978  0   0   127081
2020-03-18 21:17:06.040 340978  0   0   127081
2020-03-18 21:18:06.040 340978  0   0   127081
2020-03-18 21:19:06.040 340978  0   0   127081
2020-03-18 21:20:06.040 340984  0   0   127082    <---- timer ends

结果应该是这样的,但如果它也必须是它自己的结果,我可以稍后与上面的选择结合起来

Date_Time               PartsMade   Downtime
2020-03-18 20:45:00.000 0   
2020-03-18 21:00:00.000 0   
2020-03-18 21:15:00.000 68          00:59:00
2020-03-18 21:30:00.000 97  

【问题讨论】:

  • 这看起来是个有趣的问题。请以表格文本的形式向我们展示您期望的结果。
  • 我会将回复添加到主帖,因为我不知道如何在评论中格式化它
  • 谢谢。为什么第三排的停机时间为 59 分钟?我希望停机时间分布在各个时间段中(因此 21 小时为 0 分钟,12 小时 15 为 15 分钟,依此类推)。
  • 我想知道每个问题需要多长时间才能解决,而不是累计停机时间,不确定是否有更好的方法来解决这个问题

标签: sql sql-server sql-timestamp


【解决方案1】:

这是一个尝试。请参阅this SQLFiddle

WITH X AS (
SELECT [DateTime], part_count, pv_alarm, case when pv_alarm>0 and (lag(pv_alarm) over (order by DateTime))=0 
               then 'START' else null end as State
from mydata as M1),
XX AS (
SELECT * from X where State IS NOT NULL
),
Y AS (
SELECT [DateTime], part_count, pv_alarm, (lag(part_count) over (order by DateTime)) as prev_part_Count
  from MyData as M2
),
YY AS (
  SELECT Y.[DateTime],Y.part_count,Y.pv_alarm,'END' AS State FROM Y 
  inner join XX on Y.prev_part_count=XX.part_count
  WHERE Y.part_count <> Y.prev_part_count
)
SELECT * FROM XX
UNION ALL SELECT * FROM YY

讨论:

  • CTE X 将值 START 分配给 pv_alarm 已从前一行中的零变为本行中的非零的行中的列 State
  • CTE XX 仅选择分配了State 的那些行START。严格来说这不是必须的——它可以被折叠成 YY 和最终的 SELECT——但它使事​​情变得更清晰。
  • CTE Y 是一个助手,它将前一行的 part_count 与这一行的部件计数结合在一起。您可能认为它可以折叠到 YY 中,但 LAG() 函数必须在 SELECTORDER BY 子句中,而不是 WHERE 子句中。
  • CTE YYY 获取零件计数发生变化的行,将先前的零件计数与 CTE XX 匹配以确保我们保持在正确的跨度内,并分配值 END State
  • 最后,非 CTE 选择只返回 STARTEND 行。

输出:

DateTime                part_count      pv_alarm        State
--------                ----------      --------        -----
2020-03-18T20:21:06.04Z 340978          8               START
2020-03-18T21:20:06.04Z 340984          0               END

这不是您想要的完整信息,但希望您能从那里完成它。

【讨论】:

  • 非常感谢代码的解释!这看起来很棒!
  • 如果您有能力更改系统的架构和功能,您可以通过将LAG() 表达式替换为具体化列(即具体化prev_part_count,并标记当“pv_alarm”从零变为非零时开始自己)。当然还要添加必要的索引。
猜你喜欢
  • 2013-10-21
  • 1970-01-01
  • 2010-09-17
  • 1970-01-01
  • 1970-01-01
  • 2018-12-16
  • 1970-01-01
  • 2014-09-21
  • 1970-01-01
相关资源
最近更新 更多