Как разделить одну строку на два столбца даты и времени на несколько строк и сгруппировать по дате - PullRequest
2 голосов
/ 20 января 2020

Пример данных

Если вот такие данные, как:

ID,EQP,PREVIOUSTIME,TRANSACTIONTIME,OLDSTATE,NEWSTATE
1,HT-001,2020/01/01 12:00:00,2020/01/01 13:00:00,IDLE,RUN
2,HT-001,2020/01/01 13:00:00,2020/01/05 15:00:00,RUN,IDLE
3,HT-001,2020/01/05 15:00:00,2020/01/05 16:00:00,IDLE,RUN
4,HT-001,2020/01/05 16:00:00,2020/01/05 18:00:00,RUN,IDLE

5,HT-002,2020/01/01 12:00:00,2020/01/01 13:00:00,IDLE,RUN
6,HT-002,2020/01/01 13:00:00,2020/01/05 15:00:00,RUN,IDLE
7,HT-002,2020/01/05 15:00:00,2020/01/05 16:00:00,IDLE,RUN
8,HT-002,2020/01/05 16:00:00,2020/01/05 18:00:00,RUN,IDLE

То, что я ожидаю

запрос select * from SomeView или select * from SomeFunction(datetime_of_now) или сохранение в магазине, чтобы получить результат ниже (текущая дата 2020/01/06 12:00:00)

Date        ,EQP    ,STATE  ,COST_TIME(Hour)
2020/01/01  ,HT-001 ,IDLE   ,1
2020/01/01  ,HT-001 ,RUN    ,11
2020/01/02  ,HT-001 ,RUN    ,24
2020/01/03  ,HT-001 ,RUN    ,24
2020/01/04  ,HT-001 ,RUN    ,24
2020/01/05  ,HT-001 ,IDLE   ,7 (1+6)
2020/01/05  ,HT-001 ,RUN    ,2 (2+15)
2020/01/06  ,HT-001 ,IDLE   ,12

2020/01/01  ,HT-002 ,IDLE   ,1
2020/01/01  ,HT-002 ,RUN    ,11
2020/01/02  ,HT-002 ,RUN    ,24
2020/01/03  ,HT-002 ,RUN    ,24
2020/01/04  ,HT-002 ,RUN    ,24
2020/01/05  ,HT-002 ,IDLE   ,7 (1+6)
2020/01/05  ,HT-002 ,RUN    ,2 (2+15)
2020/01/06  ,HT-002 ,IDLE   ,12

Тестовая демонстрационная ссылка

Oracle 11g Выпуск 2 | db <> fiddle

То, что я пытался встретить с трудностями

  • Я не имею понятия разделить один день на несколько строк дат.
    Например: split одна строка предыдущего времени ~ время транзакции 01/01 ~ 01/05 по крайней мере 5 строк
  • разделить последнюю на текущую дату

1 Ответ

2 голосов
/ 20 января 2020

Используйте рекурсивное условие факторинга подзапроса, чтобы сгенерировать дневные границы и рассчитать продолжительность, а затем агрегировать:

Oracle Настройка :

CREATE TABLE table1 ( ID,EQP,PREVIOUSTIME,TRANSACTIONTIME,OLDSTATE,NEWSTATE ) AS
SELECT 1,'HT-001',DATE '2020-01-01' + INTERVAL '12:00:00' HOUR TO SECOND,DATE '2020-01-01' + INTERVAL '13:00:00' HOUR TO SECOND,'IDLE','RUN' FROM DUAL UNION ALL
SELECT 2,'HT-001',DATE '2020-01-01' + INTERVAL '13:00:00' HOUR TO SECOND,DATE '2020-01-05' + INTERVAL '15:00:00' HOUR TO SECOND,'RUN','IDLE' FROM DUAL UNION ALL
SELECT 3,'HT-001',DATE '2020-01-05' + INTERVAL '15:00:00' HOUR TO SECOND,DATE '2020-01-05' + INTERVAL '16:00:00' HOUR TO SECOND,'IDLE','RUN' FROM DUAL UNION ALL
SELECT 4,'HT-001',DATE '2020-01-05' + INTERVAL '16:00:00' HOUR TO SECOND,DATE '2020-01-05' + INTERVAL '18:00:00' HOUR TO SECOND,'RUN','IDLE' FROM DUAL UNION ALL
SELECT 5,'HT-002',DATE '2020-01-01' + INTERVAL '12:00:00' HOUR TO SECOND,DATE '2020-01-01' + INTERVAL '13:00:00' HOUR TO SECOND,'IDLE','RUN' FROM DUAL UNION ALL
SELECT 6,'HT-002',DATE '2020-01-01' + INTERVAL '13:00:00' HOUR TO SECOND,DATE '2020-01-05' + INTERVAL '15:00:00' HOUR TO SECOND,'RUN','IDLE' FROM DUAL UNION ALL
SELECT 7,'HT-002',DATE '2020-01-05' + INTERVAL '15:00:00' HOUR TO SECOND,DATE '2020-01-05' + INTERVAL '16:00:00' HOUR TO SECOND,'IDLE','RUN' FROM DUAL UNION ALL
SELECT 8,'HT-002',DATE '2020-01-05' + INTERVAL '16:00:00' HOUR TO SECOND,DATE '2020-01-05' + INTERVAL '18:00:00' HOUR TO SECOND,'RUN','IDLE' FROM DUAL UNION ALL
SELECT 9,'HT-002',DATE '2020-01-05' + INTERVAL '18:00:00' HOUR TO SECOND,DATE '2020-01-06' + INTERVAL '00:00:00' HOUR TO SECOND,'IDLE','IDLE' FROM DUAL;

Запрос :

WITH days ( eqp, dt, state, next_dt, max_dt ) AS (
  SELECT eqp,
         previoustime,
         oldstate,
         LEAST( TRUNC( previoustime ) + 1, transactiontime ),
         transactiontime
  FROM   (
    SELECT eqp,
           previoustime,
           transactiontime,
           oldstate,
           newstate
    FROM   table1
    UNION ALL
    SELECT eqp,
           MAX( transactiontime ),
           TRUNC( MAX( transactiontime ) + INTERVAL '23:59:59' HOUR TO SECOND ),
           MAX( newstate ) KEEP ( DENSE_RANK LAST ORDER BY transactiontime ),
           NULL
    FROM   table1
    GROUP BY eqp
  )
UNION ALL
  SELECT eqp,
         next_dt,
         state,
         LEAST( next_dt + 1, max_dt ),
         max_dt
  FROM   days
  WHERE  next_dt < max_dt
)
SELECT TRUNC( dt ) AS dt,
       eqp,
       state,
       SUM( ROUND( ( next_dt - dt ) * 24 ) ) AS cost_time
FROM   days
GROUP BY eqp, TRUNC( dt ), state
HAVING SUM( ROUND( ( next_dt - dt ) * 24 ) ) > 0
ORDER BY eqp, dt, state;

Вывод :

DT                  | EQP    | STATE | COST_TIME
:------------------ | :----- | :---- | --------:
2020-01-01 00:00:00 | HT-001 | IDLE  |         1
2020-01-01 00:00:00 | HT-001 | RUN   |        11
2020-01-02 00:00:00 | HT-001 | RUN   |        24
2020-01-03 00:00:00 | HT-001 | RUN   |        24
2020-01-04 00:00:00 | HT-001 | RUN   |        24
2020-01-05 00:00:00 | HT-001 | IDLE  |         7
2020-01-05 00:00:00 | HT-001 | RUN   |        17
2020-01-01 00:00:00 | HT-002 | IDLE  |         1
2020-01-01 00:00:00 | HT-002 | RUN   |        11
2020-01-02 00:00:00 | HT-002 | RUN   |        24
2020-01-03 00:00:00 | HT-002 | RUN   |        24
2020-01-04 00:00:00 | HT-002 | RUN   |        24
2020-01-05 00:00:00 | HT-002 | IDLE  |         7
2020-01-05 00:00:00 | HT-002 | RUN   |        17

db <> Fiddle здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...