如何计算列的累计数?

时间:2013-02-11 14:52:35

标签: sql oracle select view plsql

如果我已经在表格中有MYHOUR和STATUS列,并且只有这两列,我该如何创建一个视图来计算OFF_HOURS列? OFF_HOURS列是连续的“OFF”状态编号。感谢。

MYHOUR STATUS   OFF_HOURS
------ -------- --------
     1 OFF      1
     2 OFF      2
     3 ON       0
     4 ON       0
     5 ON       0
     6 ON       0
     7 ON       0
     8 OFF      1
     9 OFF      2
    10 OFF      3
    11 ON       0
    12 ON       0
    13 OFF      1
    14 OFF      2
    15 OFF      3
    16 OFF      4
    17 OFF      5
    18 OFF      6
    19 OFF      7
    20 OFF      8
    21 OFF      9
    22 OFF      10
    23 OFF      11
    24 OFF      12

以下是创建示例表和数据的脚本。

CREATE TABLE Test_Table (
myHour  INTEGER,
status VARCHAR2(8));

BEGIN
  FOR i IN 1..2
  LOOP
    INSERT INTO Test_Table VALUES (i, 'OFF');
  END LOOP;

  FOR i IN 3..7
  LOOP
    INSERT INTO Test_Table VALUES (i, 'ON');
  END LOOP;

  FOR i IN 8..10
  LOOP
    INSERT INTO Test_Table VALUES (i, 'OFF');
  END LOOP;

  FOR i IN 11..12
  LOOP
    INSERT INTO Test_Table VALUES (i, 'ON');
  END LOOP;

  FOR i IN 13..24
  LOOP
    INSERT INTO Test_Table VALUES (i, 'OFF');
  END LOOP;

  COMMIT;
END;
/

4 个答案:

答案 0 :(得分:2)

您可以使用分析:

SQL> SELECT myhour,
  2         status,
  3         CASE
  4            WHEN status = 'OFF' THEN
  5             COUNT(*)
  6                over(PARTITION BY grp ORDER BY myhour)
  7            ELSE
  8             0
  9         END off_hours
 10    FROM (SELECT myhour, status,
 11                 SUM(offwork) over(ORDER BY myhour) grp
 12            FROM (SELECT myhour,
 13                         status,
 14                         CASE
 15                            WHEN status
 16                                 != lag(status) over(ORDER BY myhour) THEN
 17                             1
 18                         END offwork
 19                    FROM Test_Table))
 20  ORDER BY myhour;

 MYHOUR STATUS    OFF_HOURS
------- -------- ----------
      1 OFF               1
      2 OFF               2
      3 ON                0
      4 ON                0
      5 ON                0
      6 ON                0
      7 ON                0
      8 OFF               1
      9 OFF               2
     10 OFF               3
     11 ON                0
     12 ON                0
     13 OFF               1
     14 OFF               2
     15 OFF               3
     16 OFF               4
     17 OFF               5
     18 OFF               6
     19 OFF               7
     20 OFF               8
     21 OFF               9
     22 OFF              10
     23 OFF              11
     24 OFF              12

更简单:

SELECT myhour,
       status,
       CASE
          WHEN status = 'OFF' THEN
           myhour - nvl(last_value(CASE WHEN status = 'ON' 
                                        THEN myhour
                                   END IGNORE NULLS) 
                                   over(ORDER BY myhour), 0) 
       END
  FROM Test_Table;

答案 1 :(得分:0)

假设MyHour值是连续的,您可以使用相关子查询最轻松地执行此操作:

select t.*,
       (select MAX(MyHour) from t t2 where t2.MyHour <= t.MyHour and t2.status = 'ON'
       ) - MyHour
from t

有一种使用分析函数的解决方案,但它更复杂。

答案 2 :(得分:0)

我认为选择count(*)from ... where status ='off'group by my hour是你要找的。

答案 3 :(得分:0)

一种选择是使用递归查询:

With CTE (myHour, status, Off_Hours) AS (
  SELECT myHour, status, CASE WHEN status = 'Off' THEN 1 ELSE 0 END as Off_Hours
  FROM Test_Table
  WHERE myHour = 1
  UNION ALL
  SELECT T.myHour, T.status,  CASE WHEN T.status = 'Off' THEN CTE.Off_Hours + 1 ELSE 0 END as Off_Hours
  FROM CTE 
     INNER JOIN Test_Table T on CTE.myHour + 1 = T.myHour
)
SELECT * FROM CTE

这是Fiddle