SQL Server:确定记录数据中条件的开始/结束时间

时间:2015-01-12 20:41:00

标签: sql sql-server-2012

长话短说我今天在生产存储过程中发现了一个问题,我们用它来记录来自我们PLC的数据,存储过程的一部分是当一行停机时将行插入日志表。当存储过程记录这些条目时,没有记录正确的开始时间,所以除了开始时间之外我有我的所有数据,如果我能弄清楚如何从我们的其余数据中确定我&# 39;没关系。

我们正在运行SQL Server 2012,并且我尝试了一些主要使用LAG()的解决方案,但我还没有能够正确使用分区子句。

sqlfiddle似乎在2012年失败了(由于IOException"架构构建错误,我得到了一个"无法连接到数据源)所以不幸的是,我所拥有的只是T-而不是T-用于样本数据的SQL。

CREATE TABLE LogData 
(
    LogID INT IDENTITY(1,1) NOT NULL --ID Column
    ,LogTime DATETIME NOT NULL --TimeStamp Column
    ,LogLineID INT NOT NULL --Machine number
    ,LogCycles INT NOT NULL --Machine cycle count
    ,LogUptime decimal(5,2) --% Machine uptime across 5 min cycles
)

--"Downtime" is defined as [LogUptime] < 0.10
INSERT INTO LogData (LogTime, LogLineID, LogCycles, LogUptime)
VALUES
      ('01/01/2014 00:05:00', 1, 90, 0.85)
     ,('01/01/2014 00:05:00', 2, 100, 1.0)
     ,('01/01/2014 00:10:00', 1, 50, 0.25)
     ,('01/01/2014 00:10:00', 2, 100, 1.0)
     ,('01/01/2014 00:15:00', 1, 0, 0.01) --Start of Downtime...what I want to determine
     ,('01/01/2014 00:15:00', 2, 100, 1.0)
     ,('01/01/2014 00:20:00', 1, 0, 0.0)
     ,('01/01/2014 00:20:00', 2, 100, 1.0)
     ,('01/01/2014 00:25:00', 1, 0, 0.0)
     ,('01/01/2014 00:25:00', 2, 100, 1.0)
     ,('01/01/2014 00:30:00', 1, 10, 0.04)
     ,('01/01/2014 00:30:00',2,100,1.0)
     ,('01/01/2014 00:35:00',1,40,0.3) --End of Downtime...what I have
     ,('01/01/2014 00:35:00',2,100,1.0)
     ,('01/01/2014 00:40:00',1,100,1.0)
     ,('01/01/2014 00:40:00',2,100,1.0)

--***Desired Result***
SELECT '01/01/2014 00:15:00' AS StartTime
    ,'01/01/2014 00:35:00' AS EndTime
    ,1 AS LineID

编辑 - 添加了部分查询

我尝试在子查询中向数据集添加一个额外的列,表示该行是否已关闭该行,然后按该列进行分区并使用LAG()并使用MIN / MAX来代替落后。 LAG只返回下一行的时间,MIN返回整个数据集中忽略分区的最小值。

SELECT LogTime AS StartTime
,LAG(LogTime) OVER (PARTITION BY LogLineUp ORDER BY LogTime DESC) AS EndTime
,LogLineID
,LogUptime
,LogLineUp
FROM (
    SELECT LogTime
        ,LogLineID
        ,LogUptime
        ,CASE WHEN LogUptime < 0.1 THEN 0 ELSE 1 END AS LogLineUp
    FROM LogData
    WHERE LogLineID = 1
) T2

1 个答案:

答案 0 :(得分:0)

感谢@VladimirBaranov修复了我的查询的LAG / LEAD部分,为我提供了一个有效的解决方案。这就是我最后的结果,我确信这种方法比嵌套的子查询更优雅,但有一次(希望)修复它对我有用。

查询的快速解释:

  • T4添加一个[LineUp]列作为标志来确定该行是向上还是向下
  • T3使用LAG()配对当前行&#34; LineUp&#34;作为[NewState]与前一行&#34; LineUp&#34;作为[PreviousState],以确定哪些行有向上/向下状态变化。
  • T2使用LEAD()将当前行时间与下一行的时间相结合,并使用where子句排除所有不涉及上/下状态更改的行。
  • 外部查询仅选择[PreviousState]为&#39; Up&#39;
  • 的行,仅选择停机时段。

我将结果放在临时表中,然后通过使用LineID&amp; amp;将该表连接到临时表来对日志条目开始时间执行更新。 EndTime列。

    SELECT StartTime
            ,EndTime
            ,LineID
    FROM (
        SELECT LogTime AS StartTime
                ,LEAD(LogTime) OVER (ORDER BY LDTime) AS EndTime
                ,LogLineID AS LineID
                ,PreviousState
        FROM (
            SELECT LogTime
                    ,LAG(LineUp) OVER (PARTITION BY LogLineID ORDER BY LogTime) AS PreviousState
                    ,LineUp AS NewState
                    ,LogLineID
                    FROM (
                        SELECT LogTime
                                ,LogLineID
                            ,CASE WHEN LogUptime < 0.1 THEN 0 ELSE 1 END AS LineUp
                        FROM LogData
                        WHERE LogLineID = 1
                    ) T4
                ) T3
        WHERE PreviousState <> NewState
        ) T2
    WHERE PreviousState = 1