Oracle SQL:计算值超过阈值的时间段

时间:2018-06-21 12:00:46

标签: sql database oracle

我的表MEASUREMENTS(Oracle SQL 12)有3列:DT-测量时间戳,MEASUREMENT-值,THRESHOLD-上限。

有时测量值超出阈值。尝试计算测量值高于阈值的时间段。

DT             | MEASUREMENT | THRESHOLD          
---------------+-------------+--------------------
04.08.16 01:10 | 60,5        | 70,0               
04.08.16 01:20 | 65,5        | 70,0               
04.08.16 01:30 | 68,1        | 70,0               
04.08.16 01:40 | 70,1*       | 70,0 //period start
04.08.16 01:50 | 70,1*       | 70,0               
04.08.16 02:00 | 70,75*      | 70,0 //period end  
04.08.16 02:10 | 53,5        | 70,0               
04.08.16 02:20 | 50,15       | 70,0               
04.08.16 02:30 | 52,15       | 70,0               
04.08.16 02:40 | 53,15       | 70,0               

预期结果(02:00-01:40 = 00:20):

DURATION | START          | END
---------+----------------+---------------
00:20    | 04.08.16 01:40 | 04.08.16 02:00

4 个答案:

答案 0 :(得分:3)

您可以使用row_number()来标识时间段。这是一个孤岛问题。以下返回测量超过阈值的每个周期:

select max(dt) - min(dt) as duration, min(dt), max(dt)
from (select t.*,
             row_number() over (order by dt) as seqnum,
             row_number() over (partition by (case when measurement > threshold then 1 else 2 end), order by dt) as seqnum_t
      from t
     ) t
where measurement > threshold
group by (seqnum - seqnum_t)

答案 1 :(得分:2)

您可以使用MATCH_RECOGNIZE子句(以及一些其他信息):

WITH t (DT, MEASUREMENT, THRESHOLD) AS (
    SELECT TO_DATE('01:10', 'hh24:mi'), 60.5  , 70 FROM dual UNION ALL
    SELECT TO_DATE('01:20', 'hh24:mi'), 65.5  , 70 FROM dual UNION ALL
    SELECT TO_DATE('01:30', 'hh24:mi'), 68.1  , 70 FROM dual UNION ALL
    SELECT TO_DATE('01:40', 'hh24:mi'), 70.1  , 70 FROM dual UNION ALL
    SELECT TO_DATE('01:50', 'hh24:mi'), 70.1  , 70 FROM dual UNION ALL
    SELECT TO_DATE('02:00', 'hh24:mi'), 70.75 , 70 FROM dual UNION ALL
    SELECT TO_DATE('02:10', 'hh24:mi'), 53.5  , 70 FROM dual UNION ALL
    SELECT TO_DATE('02:20', 'hh24:mi'), 50.15 , 70 FROM dual UNION ALL
    SELECT TO_DATE('02:30', 'hh24:mi'), 52.15 , 70 FROM dual UNION ALL
    SELECT TO_DATE('02:40', 'hh24:mi'), 53.15 , 70 FROM dual)
SELECT MEASUREMENT_MAX, match_num, FIRST_DT, LAST_DT, (LAST_DT-FIRST_DT)*24*60 AS DURATION
FROM t
    MATCH_RECOGNIZE (
        ORDER BY DT
        MEASURES 
            FINAL MAX(MEASUREMENT) AS MEASUREMENT_MAX,
            MATCH_NUMBER() AS match_num,
            FINAL LAST(DT) AS LAST_DT,
            FINAL FIRST(DT) AS FIRST_DT
        PATTERN (a+)
        DEFINE
            a AS MEASUREMENT > THRESHOLD);


MEASUREMENT_MAX    match_num   FIRST_DT              LAST_DT                DURATION
70.75              3           01.06.2018 01:40:00   01.06.2018 02:00:00    20

答案 2 :(得分:0)

使用row_number分析函数:

xmltable

输出:

...
SELECT d.dname, e.ename, e.empno
  FROM dept d
       LEFT OUTER JOIN
       (
         SELECT x.*
          FROM empdata e_data
               CROSS JOIN 
               xmltable (
                   'office/emp'
                   PASSING e_data.xcol
                   COLUMNS deptno NUMBER (28, 0) PATH 'deptno',
                           ename VARCHAR2 (10) PATH 'ename',
                           empno NUMBER (28, 0) PATH 'empno') x
        ) e
           ON d.deptno = e.deptno;

DNAME      ENAME           EMPNO
---------- ---------- ----------
Accounting Abraham             1
Accounting Alexander           2
Broking    Benjamin            3
Broking    Bradley             4
HR                              

您的查询将是:

SQL> WITH measurements (DT, MEASUREMENT, THRESHOLD) AS (
  2      select to_date('04.08.16 01:10', 'DD.MM.YY HH24:MI'), 60.5, 70.0 from dual union all
  3      select to_date('04.08.16 01:20', 'DD.MM.YY HH24:MI'), 65.5, 70.0 from dual union all
  4      select to_date('04.08.16 01:30', 'DD.MM.YY HH24:MI'), 68.1, 70.0 from dual union all
  5      select to_date('04.08.16 01:40', 'DD.MM.YY HH24:MI'), 70.1, 70.0 from dual union all
  6      select to_date('04.08.16 01:50', 'DD.MM.YY HH24:MI'), 70.1, 70.0 from dual union all
  7      select to_date('04.08.16 02:00', 'DD.MM.YY HH24:MI'), 70.75, 70.0 from dual union all
  8      select to_date('04.08.16 02:10', 'DD.MM.YY HH24:MI'), 53.5, 70.0 from dual union all
  9      select to_date('04.08.16 02:20', 'DD.MM.YY HH24:MI'), 50.15, 70.0 from dual union all
 10      select to_date('04.08.16 02:30', 'DD.MM.YY HH24:MI'), 52.15, 70.0 from dual union all
 11      select to_date('04.08.16 02:40', 'DD.MM.YY HH24:MI'), 53.15, 70.0 from dual),
 12  ---------------------
 13  ---- end of data preparation
 14  ---------------------
 15  calculated_values AS (
 16    SELECT DT,
 17           MEASUREMENT,
 18           THRESHOLD,
 19           row_number() OVER (ORDER BY dt) - row_number() OVER (PARTITION BY CASE WHEN MEASUREMENT > THRESHOLD THEN 1 ELSE 0 END ORDER BY dt) rn,
 20           CASE WHEN MEASUREMENT > THRESHOLD THEN 1 ELSE 0 END threshold_flag
 21      FROM measurements)
 22  SELECT cast(numtodsinterval(MAX(dt)-MIN(dt), 'DAY') AS INTERVAL DAY(0) TO SECOND(0)) AS duration,
 23         MIN(dt) AS "START",
 24         MAX(dt) AS  "END"
 25    FROM calculated_values
 26   WHERE threshold_flag > 0
 27   GROUP BY rn;

答案 3 :(得分:0)

您不需要使用两个row_number,可以通过累积方法直接使用它:

select max(dt) - min(dt) as duration, min(dt), max(dt)
from (select *, row_number() over (order by dt) as seq,
                sum(case when measurement > threshold then 1 else 0 end) over(order by dt) as grp
      from table
     ) t
where measurement > threshold
group by (seq - grp);