SQL Server 2012:获取出现次数并使用动态计算持续时间 SQL
SQL Server 2012 : get number of occurrences and calculate duration with Dynamic SQL
我有一个 table 过程设定点和过程值 (PV)。
如下所示 table:
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 列用于设定值。
全部合而为一 table。以 1 秒为间隔的时间戳。
知道如何对每个 PV 执行相同的查询吗?
我正在考虑 Dynamic SQL with Cursor 和下面的 CTE 选项全部组合在一起。但这真的很难。
您可以使用 lag
到 select 之前的 pv 和设置点值,以及仅 select 当前 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
第1,2,3行对应t2 t6 t9。
prev_timestamp
第2行对应t5
prev_timestamp
在第 3 行(最后一行)对应于 t8
next_timestamp
在第 3 行(最后一行)对应于 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
这是一个典型的孤岛问题。解决这个问题的步骤,
- 查找范围开始和范围结束
- 将范围开始和范围结束合并为一行
- 按范围开始分组
这是代码
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
又长又丑但它有效
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
我有一个 table 过程设定点和过程值 (PV)。
如下所示 table:
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 列用于设定值。 全部合而为一 table。以 1 秒为间隔的时间戳。 知道如何对每个 PV 执行相同的查询吗? 我正在考虑 Dynamic SQL with Cursor 和下面的 CTE 选项全部组合在一起。但这真的很难。
您可以使用 lag
到 select 之前的 pv 和设置点值,以及仅 select 当前 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
第1,2,3行对应t2 t6 t9。
prev_timestamp
第2行对应t5
prev_timestamp
在第 3 行(最后一行)对应于 t8
next_timestamp
在第 3 行(最后一行)对应于 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
这是一个典型的孤岛问题。解决这个问题的步骤,
- 查找范围开始和范围结束
- 将范围开始和范围结束合并为一行
- 按范围开始分组
这是代码
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
又长又丑但它有效
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