I have a table which contains sensor data data1
and the allowed (alarm) limits for that sensor data data1high
and data1low
. I wish to create a view where only those data1 values are listed which are the first to move outside the limits (i.e. an alarm condition) or moved back in within "safe" limits (alarm condition no longer present).
Here is a typical table:
| 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 |
The logic is that values within where data1 < data1low OR data1 > data1high
are in the alarm condition and should be listed.
For example,
| id | data1 |
|----|-------|
| 1 | 60 |
| 2 | 80 |
| 5 | 60 |
| 6 | 60 |
| 8 | 40 |
| 9 | 58 |
| 10 | 62 |
| 11 | 300 |
The table above shows all the values in the alarm state. I do not want this, only those that have just transitioned into that state and those which first values where the data1 goes back to within safe limits, so my ideal view would be:
| 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 is in alarm state so listed, id 2 is omitted because that was still in the alarm state, id 3 is listed because that is the next value to be back in limits, id 4 is omitted because that is still within limits, id 5 is listed because that is back outside limits etc ...
Here is another solution:
You can use a Recursive CTE to iterate over the rows and compare one row to the previous row, applying the logic of what you classify as a transition.
Looking at your desired output though, I don't think
id = 10
should appear in the list as it hasn't transitioned.Here's a sample that you can run in isolation to test:
Within the CTE, a column is added to mark rows that have transitioned. The
CASE WHEN
clauses contain what I can gauge as the logic you require to asses if a transition has taken place compared to the previous row.At the end of the CTE, you can simply select all rows where
Transitioned = 1
, to produce:Working Demo SQL Fiddle
If you're using SQL-Server 2012, you can use the
LAG
function:If I understood your problem correctly, you want to get all records that changed from being in alarm to not being in alarm. If that is the case, shouldn't be 11 not in the result set? The last change is 8. Records in between ( 9 and 10) is still in alarm, so is 11, so this should not be included.
SQL Fiddle