Группа запросов Oracle по последовательному значению и получению даты начала и окончания - PullRequest
1 голос
/ 21 октября 2019

У меня есть такая таблица (на самом деле, это результат большого большого запроса):

id   |  date_measured        |  out_of_range
-----+-----------------------+--------------
3147 |  09/08/2019 20.00:00  |  1
3147 |  09/08/2019 21.00:00  |  0
3147 |  09/08/2019 22.00:00  |  0
3147 |  09/08/2019 23.00:00  |  1
3147 |  10/08/2019 00.00:00  |  1
3147 |  10/08/2019 01.00:00  |  1
3147 |  10/08/2019 02.00:00  |  0
3125 |  09/08/2019 20.00:00  |  0
3125 |  09/08/2019 21.00:00  |  1
3125 |  09/08/2019 22.00:00  |  1
3125 |  09/08/2019 23.00:00  |  0
3125 |  10/08/2019 00.00:00  |  1
3125 |  10/08/2019 01.00:00  |  1
3125 |  10/08/2019 02.00:00  |  1

, и мне нужен этот результат:

id   |  date_measured_start  |  date_measured_end    |  consecutive_out_of_range
-----+-----------------------+-----------------------+--------------------------
3147 |  09/08/2019 20.00:00  |  09/08/2019 20.00:00  |  1
3147 |  09/08/2019 23.00:00  |  10/08/2019 01.00:00  |  3
3125 |  09/08/2019 21.00:00  |  09/08/2019 22.00:00  |  2
3125 |  10/08/2019 00.00:00  |  10/08/2019 02.00:00  |  3

, который является последовательнымповторение значения out_of_range = 1 и относительной даты начала и окончания.

Я пытался использовать это решение, но у меня просто не может быть только последовательный 1 для out_of_range . значение.

Ответы [ 2 ]

1 голос
/ 21 октября 2019

Здесь другое применение того же метода, что и в ответе MT0. Этот метод известен как метод «фиксированных различий» («фиксированные различия» в обоих решениях являются дополнительным вычисленным значением, по которому мы группируем данные);также известный как метод "tabibitosan".

В этом решении я вычитаю row_number() (соответствующим образом измененный) непосредственно из даты, но после выбирая только строки с флагом, равным1. Это может быть важно, если у вас очень большой объем данных, но только относительно небольшая часть строк имеет флаг, равный 1. Это потому, что row_number() необходимо упорядочить данных, изаказ дорогая операция. Чтобы решить эту проблему, нам не нужно упорядочивать (по дате) строки, где флаг равен 0 - только строки, где флаг равен 1.

EDIT (на основе MT0комментарий под этим ответом)

MT0 правильно указывает, что мое решение предполагает что-то верное в тестовых данных, опубликованных ОП, но не указано явно. А именно, что время-дата в столбце date_measured - это непрерывные последовательности даты-времени с интервалом в один час.

На самом деле, мое решение действительно заключается в следующем. Предположим, что с самого начала данные состояли только из строк вне диапазона (с флагом, равным 1), и что время-дата в столбце date_measured всегда округлялось до часа, как и вДанные испытаний ОП. Таким образом, вопрос состоит в том, чтобы идентифицировать последовательности строк, в которых времена являются «последовательными» (то есть с интервалом в один час). Вот что делает запрос.

END EDIT

Я использовал таблицу MT0 - из его теста db fiddle. Спасибо MT0!

with
  tabibitosan (id, date_measured, grp) as (
    select id, date_measured,
           date_measured 
           - row_number() over (partition by id order by date_measured) 
             * interval '1' hour
    from   table_name
    where  out_of_range = 1    
  )
select id, min(date_measured) as date_measured_start, 
           max(date_measured) as date_measured_end,
           count(*)           as consecutive_out_of_range
from   tabibitosan
group  by id, grp
order  by id, date_measured_start    --  or whatever
;

  ID DATE_MEASURED_START DATE_MEASURED_END CONSECUTIVE_OUT_OF_RANGE
---- ------------------- ----------------- ------------------------
3125 2019-08-09 21:00    2019-08-09 22:00                         2
3125 2019-08-10 00:00    2019-08-10 02:00                         3
3147 2019-08-09 20:00    2019-08-09 20:00                         1
3147 2019-08-09 23:00    2019-08-10 01:00                         3
0 голосов
/ 21 октября 2019

Используйте аналитическую функцию ROW_NUMBER, если присвойте каждой строке два возрастающих числовых значения - одно для id, а другое для пары id / out_of_range. Если вы вычтете одно из другого, то результирующее число будет постоянным в последовательном наборе строк с одинаковыми значениями id / out_of_range, и вы можете использовать это для GROUP BY:

Запрос :

SELECT id,
       MIN( date_measured ) AS date_measured_start,
       MAX( date_measured ) AS date_measured_end,
       COUNT( * ) AS consecutive_out_of_range
FROM   (
  SELECT t.*,
         ROW_NUMBER() OVER ( PARTITION BY id ORDER BY date_measured )
           - ROW_NUMBER() OVER ( PARTITION BY id, out_of_range ORDER BY date_measured )
           AS rn
  FROM   table_name t
)
WHERE out_of_range = 1
GROUP BY id, rn

Вывод :

  ID | DATE_MEASURED_START | DATE_MEASURED_END   | CONSECUTIVE_OUT_OF_RANGE
---: | :------------------ | :------------------ | -----------------------:
3147 | 2019-08-09 20:00:00 | 2019-08-09 20:00:00 |                        1
3147 | 2019-08-09 23:00:00 | 2019-08-10 01:00:00 |                        3
3125 | 2019-08-10 00:00:00 | 2019-08-10 02:00:00 |                        3
3125 | 2019-08-09 21:00:00 | 2019-08-09 22:00:00 |                        2

дБ <> скрипка здесь

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