SQL 在没有游标的情况下迭代行
SQL Iterate over row without a cursor
我有一些数据可以读取传感器的状态。传感器每 15 分钟报告一次状态。这有点像...
Sensor ID, Status, TimeStamp, **WhatIWantSessionID**
1, Off, 0345, **0**
1, Charge, 0400, **1**
1, Charge, 0415, **1**
1, Off, 0430, **0**
1, Charge, 0445, **2**
1, Off, 0500, **0**
"WhatIWantSessionID" ...我想在每次收费会话开始时设置一个递增的 sessionID。保持该 sessionID 直到状态切换状态。下面的 link 非常棒,“几乎”满足了我的需要,但还不够(因为我在会话期间没有 start/stop 的标志)。帮助非常感谢。
必须有更好的方法来做到这一点,但下面的示例有效(丑陋,我相信有人会 post 一些聪明而聪明的东西,但我还没有受够咖啡今天还没做聪明,而且有效)。
create or replace temporary table stacko_64351844 (
id number,
status varchar(20),
ts varchar(20),
desired number);
INSERT INTO stacko_64351844
VALUES
(1, 'Off', '0345', 0),
(1, 'Charge', '0400', 1),
(1, 'Charge', '0415', 1),
(1, 'Off', '0430', 0),
(1, 'Charge', '0445', 2),
(1, 'Off', '0500', 0),
(1, 'Charge', '0515', 3),
(1, 'Charge', '0530', 3),
(1, 'Charge', '0545', 3),
(1, 'Charge', '0600', 3),
(1, 'Off', '0615', 0);
SELECT id,
status, ts,
desired,
NVL(calc_desired, max(calc_desired) over (partition by id order by id, ts rows between unbounded preceding and current row)) as calc_desired
FROM (
SELECT id,
status,
ts,
desired,
tmp_desired,
CASE
WHEN status = 'Off' THEN 0
WHEN (status != 'Charge' AND status = lag(status, 1, null)
over (partition by id order by id, ts, status DESC) )
THEN null
ELSE
sum(tmp_desired) over (partition by id, tmp_desired order by id, ts rows between unbounded preceding and current row)
end as calc_desired
FROM (
SELECT id,
status,
ts,
desired,
CASE
WHEN status = 'Off' THEN 0
WHEN status = lag(status, 1, null)
over (partition by id order by id, ts, status DESC)
THEN null
ELSE
1
end as tmp_desired
FROM stacko_64351844)
ORDER BY id, ts, status DESC);
RESULTS
ID STATUS TS DESIRED CALC_DESIRED
1 Off 0345 0 0
1 Charge 0400 1 1
1 Charge 0415 1 1
1 Off 0430 0 0
1 Charge 0445 2 2
1 Off 0500 0 0
1 Charge 0515 3 3
1 Charge 0530 3 3
1 Charge 0545 3 3
1 Charge 0600 3 3
1 Off 0615 0 0
希望对你有所帮助...丰富
p.s。如果这个(或另一个)答案对您有帮助,请花点时间“接受”有帮助的答案
通过单击答案旁边的复选标记将其从“灰色”切换为“已填写”。
MSSQL,但 sure/hope 它可以在 ansi 上运行。
感谢 Rich Murnane 的数据提示
create TABLE #stacko_64351844 (
id int,
status varchar(20),
ts varchar(20),
desired int);
INSERT INTO #stacko_64351844
VALUES
(1, 'Off', '0345', 0),
(1, 'Charge', '0400', 1),
(1, 'Charge', '0415', 1),
(1, 'Off', '0430', 0),
(1, 'Charge', '0445', 2),
(1, 'Off', '0500', 0),
(1, 'Charge', '0515', 3),
(1, 'Charge', '0530', 3),
(1, 'Charge', '0545', 3),
(1, 'Charge', '0600', 3),
(1, 'Off', '0615', 0);
SELECT CASE status WHEN 'off' THEN 0
else SUM(CASE WHEN lg='off' THEN 1 ELSE 0 END) OVER(PARTITION BY id ORDER BY ts) END DesiredCalc
,t.id,t.status,t.ts,t.desired FROM (
SELECT LAG(status)OVER(PARTITION BY id ORDER BY ts)lg,* FROM #stacko_64351844
)t
ORDER BY ts
结果:
DesiredCalc id status ts desired
0 1 Off 0345 0
1 1 Charge 0400 1
1 1 Charge 0415 1
0 1 Off 0430 0
2 1 Charge 0445 2
0 1 Off 0500 0
3 1 Charge 0515 3
3 1 Charge 0530 3
3 1 Charge 0545 3
3 1 Charge 0600 3
0 1 Off 0615 0
我有一些数据可以读取传感器的状态。传感器每 15 分钟报告一次状态。这有点像...
Sensor ID, Status, TimeStamp, **WhatIWantSessionID**
1, Off, 0345, **0**
1, Charge, 0400, **1**
1, Charge, 0415, **1**
1, Off, 0430, **0**
1, Charge, 0445, **2**
1, Off, 0500, **0**
"WhatIWantSessionID" ...我想在每次收费会话开始时设置一个递增的 sessionID。保持该 sessionID 直到状态切换状态。下面的 link 非常棒,“几乎”满足了我的需要,但还不够(因为我在会话期间没有 start/stop 的标志)。帮助非常感谢。
必须有更好的方法来做到这一点,但下面的示例有效(丑陋,我相信有人会 post 一些聪明而聪明的东西,但我还没有受够咖啡今天还没做聪明,而且有效)。
create or replace temporary table stacko_64351844 (
id number,
status varchar(20),
ts varchar(20),
desired number);
INSERT INTO stacko_64351844
VALUES
(1, 'Off', '0345', 0),
(1, 'Charge', '0400', 1),
(1, 'Charge', '0415', 1),
(1, 'Off', '0430', 0),
(1, 'Charge', '0445', 2),
(1, 'Off', '0500', 0),
(1, 'Charge', '0515', 3),
(1, 'Charge', '0530', 3),
(1, 'Charge', '0545', 3),
(1, 'Charge', '0600', 3),
(1, 'Off', '0615', 0);
SELECT id,
status, ts,
desired,
NVL(calc_desired, max(calc_desired) over (partition by id order by id, ts rows between unbounded preceding and current row)) as calc_desired
FROM (
SELECT id,
status,
ts,
desired,
tmp_desired,
CASE
WHEN status = 'Off' THEN 0
WHEN (status != 'Charge' AND status = lag(status, 1, null)
over (partition by id order by id, ts, status DESC) )
THEN null
ELSE
sum(tmp_desired) over (partition by id, tmp_desired order by id, ts rows between unbounded preceding and current row)
end as calc_desired
FROM (
SELECT id,
status,
ts,
desired,
CASE
WHEN status = 'Off' THEN 0
WHEN status = lag(status, 1, null)
over (partition by id order by id, ts, status DESC)
THEN null
ELSE
1
end as tmp_desired
FROM stacko_64351844)
ORDER BY id, ts, status DESC);
RESULTS
ID STATUS TS DESIRED CALC_DESIRED
1 Off 0345 0 0
1 Charge 0400 1 1
1 Charge 0415 1 1
1 Off 0430 0 0
1 Charge 0445 2 2
1 Off 0500 0 0
1 Charge 0515 3 3
1 Charge 0530 3 3
1 Charge 0545 3 3
1 Charge 0600 3 3
1 Off 0615 0 0
希望对你有所帮助...丰富
p.s。如果这个(或另一个)答案对您有帮助,请花点时间“接受”有帮助的答案 通过单击答案旁边的复选标记将其从“灰色”切换为“已填写”。
MSSQL,但 sure/hope 它可以在 ansi 上运行。 感谢 Rich Murnane 的数据提示
create TABLE #stacko_64351844 (
id int,
status varchar(20),
ts varchar(20),
desired int);
INSERT INTO #stacko_64351844
VALUES
(1, 'Off', '0345', 0),
(1, 'Charge', '0400', 1),
(1, 'Charge', '0415', 1),
(1, 'Off', '0430', 0),
(1, 'Charge', '0445', 2),
(1, 'Off', '0500', 0),
(1, 'Charge', '0515', 3),
(1, 'Charge', '0530', 3),
(1, 'Charge', '0545', 3),
(1, 'Charge', '0600', 3),
(1, 'Off', '0615', 0);
SELECT CASE status WHEN 'off' THEN 0
else SUM(CASE WHEN lg='off' THEN 1 ELSE 0 END) OVER(PARTITION BY id ORDER BY ts) END DesiredCalc
,t.id,t.status,t.ts,t.desired FROM (
SELECT LAG(status)OVER(PARTITION BY id ORDER BY ts)lg,* FROM #stacko_64351844
)t
ORDER BY ts
结果:
DesiredCalc id status ts desired
0 1 Off 0345 0
1 1 Charge 0400 1
1 1 Charge 0415 1
0 1 Off 0430 0
2 1 Charge 0445 2
0 1 Off 0500 0
3 1 Charge 0515 3
3 1 Charge 0530 3
3 1 Charge 0545 3
3 1 Charge 0600 3
0 1 Off 0615 0