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