SQL条件语句,其中包含限制和上一个值

SQL条件语句,其中包含限制和上一个值,sql,sql-server,Sql,Sql Server,我有一个表,其中包含传感器数据data1以及传感器数据data1high和data1low的允许报警限值。我希望创建一个视图,其中仅列出那些最先超出限制(即报警条件)或在安全限制内移动的data1值。报警条件不再存在 以下是一个典型的表格: | id | data1 | data1high | data1low | |----|-------|-----------|----------| | 1 | 60 | 200 | 100 | | 2 | 80 |

我有一个表,其中包含传感器数据data1以及传感器数据data1high和data1low的允许报警限值。我希望创建一个视图,其中仅列出那些最先超出限制(即报警条件)或在安全限制内移动的data1值。报警条件不再存在

以下是一个典型的表格:

| id | data1 | data1high | data1low | 
|----|-------|-----------|----------|
|  1 |    60 |       200 |      100 |
|  2 |    80 |       200 |      100 |
|  3 |   123 |       200 |      100 |
|  4 |   150 |       200 |      100 |
|  5 |    60 |       200 |      100 |
|  6 |    60 |       200 |      100 | 
|  7 |   150 |       200 |      100 |
|  8 |    40 |       200 |      100 |
|  9 |    58 |       200 |      100 |
| 10 |    62 |       200 |      100 |
| 11 |   300 |       200 |      100 | 
逻辑是,其中data1data1high的值处于报警状态,应列出

比如说,

| id | data1 |
|----|-------|
|  1 |    60 |
|  2 |    80 |
|  5 |    60 |
|  6 |    60 |
|  8 |    40 |
|  9 |    58 |
| 10 |    62 |
| 11 |   300 |
上表显示了处于报警状态的所有值。我不希望这样,只希望那些刚刚转换到该状态的数据,以及那些数据1返回到安全限制内的第一个值,因此我的理想视图是:

| id | data1 | data1high | data1low | 
|----|-------|-----------|----------|
|  1 |    60 |       200 |      100 |
|  3 |   123 |       200 |      100 |
|  5 |    60 |       200 |      100 | 
|  7 |   150 |       200 |      100 |
|  8 |    40 |       200 |      100 |
| 11 |   300 |       200 |      100 |
id 1处于报警状态,因此被列出,id 2被忽略,因为它仍然处于报警状态,id 3被列出,因为它是下一个要返回限制的值,id 4被忽略,因为它仍然在限制内,id 5被列出是因为它又超出了限制等…

您可以使用a来迭代行,并将一行与前一行进行比较,应用您分类为转换的逻辑

但是,看看您想要的输出,我认为id=10不应该出现在列表中,因为它还没有转换

以下是一个可以单独运行以进行测试的示例:

CREATE TABLE #Data1
    (
      [id] INT ,
      [data1] INT ,
      [data1high] INT ,
      [data1low] INT
    );

INSERT  INTO #Data1
        ( [id], [data1], [data1high], [data1low] )
VALUES  ( 1, 60, 200, 100 ),
        ( 2, 80, 200, 100 ),
        ( 3, 123, 200, 100 ),
        ( 4, 150, 200, 100 ),
        ( 5, 60, 200, 100 ),
        ( 6, 60, 200, 100 ),
        ( 7, 150, 200, 100 ),
        ( 8, 40, 200, 100 ),
        ( 9, 58, 200, 100 ),
        ( 10, 62, 200, 100 ),
        ( 11, 300, 200, 100 );
WITH    cte
          AS ( SELECT TOP 1
                        id ,
                        data1 ,
                        data1high ,
                        data1low ,
                        CASE WHEN data1 < data1low
                                  OR data1 > data1high THEN 1
                             ELSE 0
                        END AS Transitioned
               FROM     #Data1
               ORDER BY id
               UNION ALL
               SELECT   #Data1.id ,
                        #Data1.data1 ,
                        #Data1.data1high ,
                        #Data1.data1low ,
                        CASE WHEN cte.data1 < cte.data1low
                                  AND #Data1.data1 < #Data1.data1low THEN 0
                             WHEN cte.data1 > cte.data1high
                                  AND #Data1.data1 < #Data1.data1high THEN 0
                             WHEN cte.data1 BETWEEN cte.data1low AND cte.data1high
                                  AND #Data1.data1 BETWEEN #Data1.data1low
                                                   AND     #Data1.data1high
                             THEN 0
                             WHEN cte.Transitioned = 1
                                  AND #Data1.data1 BETWEEN #Data1.data1low
                                                   AND     #Data1.data1high
                             THEN 1
                             ELSE 1
                        END AS Transitioned
               FROM     #Data1
                        INNER JOIN cte ON cte.id + 1 = #Data1.id
             )
    SELECT  *
    FROM    cte
    WHERE   cte.Transitioned = 1

DROP TABLE #Data1

如果您使用的是SQL Server 2012,则可以使用LAG函数:

如果我正确理解了您的问题,您希望获取所有从处于报警状态更改为不处于报警状态的记录。如果是这样,结果集中不应该是11吗?最后一个零钱是8。9到10之间的记录仍处于报警状态,11也处于报警状态,因此不应将其包括在内

WITH CteAlarm AS(
    SELECT *,
        alarm = CASE WHEN data1 < data1low OR data1 > data1high THEN 1 ELSE 0 END
    FROM test
),
Cte AS(
    SELECT *,
        prevAlarm = LAG(alarm) OVER(ORDER BY id)
    FROM CteAlarm
)
SELECT * 
FROM Cte
WHERE 
    alarm <> prevAlarm
    OR (prevAlarm IS NULL AND alarm = 1)

下面是另一个解决方案:

DECLARE @t TABLE
    (
      id INT ,
      data1 INT ,
      data1high INT ,
      data1low INT
    )

INSERT  INTO @t
VALUES  ( 1, 60, 200, 100 ),
        ( 2, 80, 200, 100 ),
        ( 3, 123, 200, 100 ),
        ( 4, 150, 200, 100 ),
        ( 5, 60, 200, 100 ),
        ( 6, 60, 200, 100 ),
        ( 7, 150, 200, 100 ),
        ( 8, 40, 200, 100 ),
        ( 9, 58, 200, 100 ),
        ( 10, 62, 200, 100 ),
        ( 11, 300, 200, 100 )


;WITH t AS(SELECT *, CASE WHEN data1 < data1low or data1 > data1high THEN 1 ELSE 0 END b
           FROM @t)
SELECT * FROM t t1 
WHERE b <> (SELECT TOP 1 b FROM t t2 WHERE t2.id < t1.id ORDER BY t2.id DESC) OR
      id = (SELECT MIN(id) FROM t) OR
      id = (SELECT MAX(id) FROM t)    

您使用的是什么版本的sql server?我不明白逻辑:请您详细说明一下。通过逻辑分析,我有一个问题,前两个实例是正确提供给您的。您需要数据的第三个快照。如果我错了,请纠正我@user3238504@user3238504为什么10和11出现了,8超出了限制,而它们仍然超出了限制?@Wewesthemenance-版本11。感谢您提供了这个全面的解决方案-您似乎完全理解了我的逻辑,并提供了一个有效的解决方案:-您是正确的,id 10是我的一个错误。这几乎是正确的逻辑。我想捕捉从进入和离开警报的过渡@Tanner有正确的逻辑和结果。@user3238504,但为什么仍然包括11?自记录8以来,它仍然没有从处于报警状态更改?它已从低报警状态更改为高报警状态。我想这就是为什么我建议它更像是一个过渡检测器。。。
DECLARE @t TABLE
    (
      id INT ,
      data1 INT ,
      data1high INT ,
      data1low INT
    )

INSERT  INTO @t
VALUES  ( 1, 60, 200, 100 ),
        ( 2, 80, 200, 100 ),
        ( 3, 123, 200, 100 ),
        ( 4, 150, 200, 100 ),
        ( 5, 60, 200, 100 ),
        ( 6, 60, 200, 100 ),
        ( 7, 150, 200, 100 ),
        ( 8, 40, 200, 100 ),
        ( 9, 58, 200, 100 ),
        ( 10, 62, 200, 100 ),
        ( 11, 300, 200, 100 )


;WITH t AS(SELECT *, CASE WHEN data1 < data1low or data1 > data1high THEN 1 ELSE 0 END b
           FROM @t)
SELECT * FROM t t1 
WHERE b <> (SELECT TOP 1 b FROM t t2 WHERE t2.id < t1.id ORDER BY t2.id DESC) OR
      id = (SELECT MIN(id) FROM t) OR
      id = (SELECT MAX(id) FROM t)