SQL Oracle Counting Clusters

前端 未结 4 849
青春惊慌失措
青春惊慌失措 2020-12-20 23:44

I have a data set which is based on a timestamp.

     Date                 Value
07-Jul-15 12:05:00          1  
07-Jul-15 12:10:00          1 
07-Jul-15 12:         


        
相关标签:
4条回答
  • 2020-12-21 00:32

    Using LEAD and LAG functions in ORACLE you can built these queries:

    1.Number of shutdowns:

    WITH IntTable AS
    ( SELECT * FROM
      (
       SELECT dt b_date,value,LEAD(dt) OVER (ORDER BY dt) e_date  FROM
         (
            select "Date" dt,"Value" value,
                   LAG("Value") OVER (ORDER BY "Date") pvalue,
                   LEAD("Value") OVER (ORDER BY "Date") nvalue
            from T
         ) T1
         WHERE pvalue is NULL or value<>pvalue or nvalue is NULL 
       )
    WHERE E_DATE is NOT NULL
    )
    SELECT COUNT(*) FROM IntTable where value = 0 
    

    SQLFiddle demo

    2.Period Between every shut down

    WITH IntTable AS
    ( SELECT * FROM
      (
       SELECT dt b_date,value,LEAD(dt) OVER (ORDER BY dt) e_date  FROM
         (
            select "Date" dt,"Value" value,
                   LAG("Value") OVER (ORDER BY "Date") pvalue,
                   LEAD("Value") OVER (ORDER BY "Date") nvalue
            from T
         ) T1
         WHERE pvalue is NULL or value<>pvalue or nvalue is NULL 
       )
    WHERE E_DATE is NOT NULL
    )
    SELECT b_date,e_date, (e_date-b_date) * 60 * 24 FROM IntTable where value = 1 
    

    SQLFiddle demo

    0 讨论(0)
  • 2020-12-21 00:34

    Hi i have tried with below code it's displaying results as expected

    with cte
        as
        (
        select Rownum rn,a.* from table a 
        )
        select date1 as start_time,endtime,  (endtime-date1)*24*60 as period 
        from 
        (
        select date1,value,case 
        when 
        value=1 then
        lead(date1) over (order by date1)
        else null
        end
         as endtime
        from
        (
        select date1,value from cte where cte.rn=1
        union all
        select a.date1,a.value from cte a
        join
        cte b
        on 
        a.rn=b.rn+1
        and( (a.value=1 and b.value=0) or (a.value=0 and b.value=1)) 
        ) order by date1) where value=1
    
    0 讨论(0)
  • 2020-12-21 00:42

    Your question has two parts, and both needs to be handled in two different queries. As the output is based on two different sets of rows.

    Setup

    SQL> CREATE TABLE t AS SELECT * FROM(WITH DATA(dt, status) AS(
      2  SELECT to_date('07-Jul-15 12:05:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1 FROM dual UNION ALL
      3  SELECT to_date('07-Jul-15 12:10:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
      4  SELECT to_date('07-Jul-15 12:15:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
      5  SELECT to_date('07-Jul-15 12:20:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 0  FROM dual UNION ALL
      6  SELECT to_date('07-Jul-15 12:25:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 0  FROM dual UNION ALL
      7  SELECT to_date('07-Jul-15 12:30:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 0  FROM dual UNION ALL
      8  SELECT to_date('07-Jul-15 12:35:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
      9  SELECT to_date('07-Jul-15 12:40:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
     10  SELECT to_date('07-Jul-15 12:45:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
     11  SELECT to_date('07-Jul-15 12:50:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
     12  SELECT to_date('07-Jul-15 12:55:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 0  FROM dual UNION ALL
     13  SELECT to_date('07-Jul-15 13:00:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 0  FROM dual UNION ALL
     14  SELECT to_date('07-Jul-15 13:05:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
     15  SELECT to_date('07-Jul-15 13:10:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
     16  SELECT to_date('07-Jul-15 13:15:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 1  FROM dual UNION ALL
     17  SELECT to_date('07-Jul-15 13:20:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 0  FROM dual UNION ALL
     18  SELECT to_date('07-Jul-15 13:25:00', 'dd-Mon-rr hh24:mi:ss', 'NLS_DATE_LANGUAGE=AMERICAN'), 0  FROM dual
     19  ) SELECT * FROM DATA);
    
    Table created.
    

    Table data

    SQL> SELECT * FROM t;
    
    DT                     STATUS
    ------------------ ----------
    07-Jul-15 12:05:00          1
    07-Jul-15 12:10:00          1
    07-Jul-15 12:15:00          1
    07-Jul-15 12:20:00          0
    07-Jul-15 12:25:00          0
    07-Jul-15 12:30:00          0
    07-Jul-15 12:35:00          1
    07-Jul-15 12:40:00          1
    07-Jul-15 12:45:00          1
    07-Jul-15 12:50:00          1
    07-Jul-15 12:55:00          0
    07-Jul-15 13:00:00          0
    07-Jul-15 13:05:00          1
    07-Jul-15 13:10:00          1
    07-Jul-15 13:15:00          1
    07-Jul-15 13:20:00          0
    07-Jul-15 13:25:00          0
    
    17 rows selected.
    
    1. Number of shutdowns: The Number of shut down in this case is 3 based on 0 is ON and 1 is OFF.

    You need to use LAG() analytic function.

    SQL> SELECT TO_CHAR(dt, 'dd-Mon-rr hh24:mi:ss') dt,
      2    status
      3  FROM
      4    (SELECT t.*,
      5      CASE
      6        WHEN lag(status) OVER(ORDER BY dt) <> status
      7        THEN 1
      8        ELSE 0
      9      END chg
     10    FROM t
     11    )
     12  WHERE status = 0
     13  AND chg      =1;
    
    DT                     STATUS
    ------------------ ----------
    07-Jul-15 12:20:00          0
    07-Jul-15 12:55:00          0
    07-Jul-15 13:20:00          0
    

    So, there are 3 rows in the output, which means 3 times the shutdown event occurred. To get the count, you just need to use the COUNT function.

    1. Period Between every shut down

    Example:

    1. From: 07-Jul-15 12:05:00 To: 07-Jul-15 12:15:00 Duration : 15 Mins
    2. From: 07-Jul-15 12:35:00 To: 07-Jul-15 12:50:00 Duration : 20 Mins

    Once again, you need to use LAG() analytic function. Difference between dates returns number of days. To convert it into minutes, multiply it with 24*60.

    SQL> SELECT * FROM(
      2  SELECT t.*,
      3      CASE
      4        WHEN lag(status) OVER(ORDER BY dt) <> status
      5        THEN 1
      6        ELSE 0
      7      END chg,
      8      24*60*(dt - lag(dt) over(order by dt)) gap
      9    FROM t
     10    ) t
     11  WHERE status =1 and chg =0;
    
    DT                     STATUS        CHG        GAP
    ------------------ ---------- ---------- ----------
    07-Jul-15 12:05:00          1          0
    07-Jul-15 12:10:00          1          0          5
    07-Jul-15 12:15:00          1          0          5
    07-Jul-15 12:40:00          1          0          5
    07-Jul-15 12:45:00          1          0          5
    07-Jul-15 12:50:00          1          0          5
    07-Jul-15 13:10:00          1          0          5
    07-Jul-15 13:15:00          1          0          5
    
    8 rows selected.
    
    SQL>
    

    So, based on above query, to find the total time when the system was up, use SUM.

    SQL> SELECT SUM(gap) on_minutes FROM(
      2  SELECT t.*,
      3      CASE
      4        WHEN lag(status) OVER(ORDER BY dt) <> status
      5        THEN 1
      6        ELSE 0
      7      END chg,
      8      24*60*(dt - lag(dt) over(order by dt)) gap
      9    FROM t
     10    ) t
     11  WHERE status =1 and chg =0;
    
    ON_MINUTES
    ----------
            35
    
    SQL>
    

    So, the system was up for 35 minutes.

    0 讨论(0)
  • 2020-12-21 00:44

    You can test my answer on sqlfiddle: http://www.sqlfiddle.com/#!4/9c6a69/16

    Test Data

    create table test (dttm date, onoff number);
    
    insert into test values (to_date('07-Jul-15 12:05:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 12:10:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 12:15:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 12:20:00', 'DD-MM-YY HH24:MI:SS'), 0 );
    insert into test values (to_date('07-Jul-15 12:25:00', 'DD-MM-YY HH24:MI:SS'), 0 );
    insert into test values (to_date('07-Jul-15 12:30:00', 'DD-MM-YY HH24:MI:SS'), 0 );
    insert into test values (to_date('07-Jul-15 12:35:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 12:40:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 12:45:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 12:50:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 12:55:00', 'DD-MM-YY HH24:MI:SS'), 0 );
    insert into test values (to_date('07-Jul-15 13:00:00', 'DD-MM-YY HH24:MI:SS'), 0 );
    insert into test values (to_date('07-Jul-15 13:05:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 13:10:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 13:15:00', 'DD-MM-YY HH24:MI:SS'), 1 );
    insert into test values (to_date('07-Jul-15 13:20:00', 'DD-MM-YY HH24:MI:SS'), 0 );
    insert into test values (to_date('07-Jul-15 13:25:00', 'DD-MM-YY HH24:MI:SS'), 0 );
    

    First of all, remove all unnecessary columns and keep only the on/off columns:

    select t.dttm, t.onoff from test t
    where not exists (select 'X' from test tt 
                      where tt.dttm =
                        (select max(ttt.dttm) from test ttt where ttt.dttm < t.dttm)
                 and tt.onoff = t.onoff)
    

    number of shutdowns:

    with data as (
    select t.dttm, t.onoff from test t
    where not exists (select 'X' from test tt 
                     where tt.dttm =
                        (select max(ttt.dttm) from test ttt where ttt.dttm < t.dttm)
                     and tt.onoff = t.onoff)
    )
    select count(*) from data d where d.onoff=0;                                
    

    ontime:

    with data as (
    select t.dttm, t.onoff from test t
    where not exists (select 'X' from test tt 
                     where tt.dttm =
                        (select max(ttt.dttm) from test ttt where ttt.dttm < t.dttm)
                     and tt.onoff = t.onoff)
    )
    select d1.dttm as ontime, 
    d0.dttm as offtime, 
    (d0.dttm - d1.dttm) * 24 * 60 as duration 
    from data d0, data d1 
    where d1.onoff=1 
    and d0.dttm = (select min(dd0.dttm) from data dd0 where dd0.dttm > d1.dttm);                                
    
    0 讨论(0)
提交回复
热议问题