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