我有一个过程设定值和过程值(PV)表。
如下表所示:
Timestamp Setpoint PV
--------- --------- -------------
t1 100 125
t2 100 95 *
t3 100 98
t4 100 88
t5 100 105
t6 100 59 *
t7 100 90
t8 100 101
t9 100 70 *
t10 100 101
我想要做的是创建一行作为结果的查询,以计算PV低于设定点并返回到设定点之上的次数。并计算它低于设定值的持续时间。
结果应该是这样的。
NumberofOccurance Duration
------------------ ---------
3 (t5-t2)+(t8-t6)+(t10-t9)
注意:正确的出现次数为 3 ,在这种情况下 6 而且我认为最困难的部分是持续时间。
有什么想法吗?
提前致谢
编辑:我在下面得到了几个好的答案,但是,如果我有一个以上的PV怎么样(我实际上在不同的列中有10个不同的PV,在每个PV的两个独立列中有两个设定点,即20列对于设定点。 都在一张桌子上。时间戳以1秒为间隔。 知道如何为每一个PV做同样的查询吗? 我正在考虑将动态SQL与Cursor和CTE选项结合在一起。但这真的很难。答案 0 :(得分:3)
您可以使用lag
选择之前的pv和设定值,并仅选择当前pv低于设定值但前一个pv不低于之前设定值的行:
select *
from (
select *,
lag(Setpoint) over (order by Timestamp) previous_setpoint,
lag(PV) over (order by Timestamp) previous_pv
from Table1
) t where PV < Setpoint
and previous_pv >= previous_setpoint
要获得持续时间和上面查询中pv
的负值,即-t2 -t6 -t9
。棘手的部分是积极的价值观。对于第一行添加任何内容。对于除第一个和最后一个之外的所有行,仅添加previous_pv
。对于最后一行,添加next_pv
和previous_pv
。
Timestamp
对应于t2 t6 t9。
第2行中的prev_timestamp
对应于t5
第3行(最后一行)中的prev_timestamp
对应于t8
第3行(最后一行)中的next_timestamp
对应于t10
select count(*), sum(case
when rn_asc = 1 then -Timestamp
when rn_desc = 1 then -Timestamp + next_timestamp + prev_timestamp
else -Timestamp + prev_timestamp
end)
from (
select *,
row_number() over (order by Timestamp) rn_asc,
row_number() over (order by Timestamp desc) rn_desc
from (
select *,
lag(Setpoint) over (order by Timestamp) previous_setpoint,
lag(PV) over (order by Timestamp) previous_pv,
lag(Timestamp) over (order by Timestamp) prev_timestamp,
lead(Timestamp) over (order by Timestamp) next_timestamp
from Table1
) t where PV < Setpoint
and previous_pv >= previous_setpoint
) t
答案 1 :(得分:2)
漫长而丑陋但它有效
CREATE TABLE MyTable
(
TimeSt INT,
SetPoint INT,
PV INT
)
INSERT INTO MyTable
VALUES (1, 100, 122),
(2, 100, 95),
(3, 100, 98),
(4, 100, 88),
(5, 100, 105),
(6, 100, 59),
(7, 100, 90),
(8, 100, 101),
(9, 100, 70),
(10, 100, 101);
WITH CTE
AS (SELECT
*
,lag(TimeSt, 1) OVER(ORDER BY TimeSt) AS LagTimeSt
,lag(SetPoint, 1) OVER(ORDER BY TimeSt) AS LagSetPoint
,lag(PV, 1) OVER(ORDER BY TimeSt) AS LagPV
FROM
MyTable),
CTE2
AS (SELECT
*
,CASE
WHEN (PV < SetPoint AND LagPV > LagSetPoint)
THEN 1 ELSE 0 END AS FirstDrop
FROM
CTE
WHERE
(PV < SetPoint AND LagPV > LagSetPoint)
OR (PV > SetPoint AND LagPV < LagSetPoint)),
CTE3
AS (SELECT
Lead(timest) OVER(ORDER BY TimeSt) UpTime
,*
FROM
CTE2)
SELECT
sum(firstDrop) AS Occur
,sum(uptime - Timest) AS DownTime
FROM
CTE3
Where FirstDrop = 1
答案 2 :(得分:1)
这是一个典型的岛屿问题。解决这个问题的步骤,
这是代码
WITH T0 AS
(
SELECT [Timestamp], CASE WHEN PV >= SetPoint THEN 1 ELSE 0 END AS pvType
FROM table
),
T1 AS
(
SELECT [Timestamp],
CASE
WHEN LAG(pvType) OVER(ORDER BY [Timestamp]) = 1 AND pvType = 0 THEN 1
ELSE 0
END AS pvStart,
CASE
WHEN LAG(pvType) OVER(ORDER BY [Timestamp]) = 0 AND pvType = 1 THEN 1
ELSE 0
END AS pvEnd
FROM T0
),
T2 AS
(
SELECT [Timestamp] AS timestampStart,
CASE
WHEN pvEnd = 1 THEN [Timestamp]
ELSE LEAD([Timestamp]) OVER(ORDER BY [Timestamp])
END AS timestampEnd,
pvStart
FROM T1
WHERE pvStart = 1 OR pvEnd = 1
)
SELECT
COUNT(*) AS Occurance,
-- Depending Timestamp type, you may want DATEDIFF
SUM(timestampEnd - timestampStart) AS Duration
FROM T2
WHERE pvStart = 1