Первое, что нам нужно, это способ сравнения FAIL_TIME. Поскольку вы не разместили структуру таблицы, предположим, что мы имеем дело со строками.
У Oracle есть некоторые аккуратные встроенные функции для дат и строк литья. Если мы конкатенации ACTIVITY_DATE и FAIL_TIME мы можем преобразовать их в тип данных Дата:
to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss')
Мы можем бросить, что в строку, представляющую число секунд за полночь:
to_char(to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss'), 'sssss')
Тогда мы можем бросить что - число, которое мы можем использовать в некоторой арифметике для сравнения с другими строками; десять минут = 600 секунд.
Далее мы можем использовать факторинг подзапроса (предложение WITH). Одна из опрятных особенностей этого синтаксиса состоит в том, что мы можем передать вывод одного подзапроса в другой, поэтому нам нужно только написать это gnarly вложенное выражение выражения один раз.
with t as
(select OFFICE_ID
, ACTIVITY_DAY
, FAIL_TIME
, to_number(to_char(to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss'), 'sssss')) FAIL_TIME_SSSSS
, CLIENT
from faillog
)
Мы можем использовать этот подзапрос для создания других подзапросов, отделяющие строки таблицы в наборы для каждого клиента для использования в нашем главном запросе.
Наконец, мы можем использовать аналитическую функцию COUNT(), чтобы отслеживать, сколько пучков FAIL_TIME у нас есть для каждой комбинации OFFICE и ACTIVITY_DATE.
count(*) over (partition by a.OFFICE_ID, a.ACTIVITY_DAY)
Собираем все вместе в целях поточного позволяет проверить, можно ли «объявить пост закрытым».
select * from (
with t as (select OFFICE_ID
, ACTIVITY_DAY
, FAIL_TIME
, to_number(to_char(to_date(ACTIVITY_DAY||' '||FAIL_TIME, 'dd/mm/yyyy hh24:mi:ss'), 'sssss')) FAIL_TIME_SSSSS
, CLIENT
from faillog
)
, a as (select *
from t
where CLIENT = 'A')
, b as (select *
from t
where CLIENT = 'B')
, c as (select *
from t
where CLIENT = 'C')
select a.OFFICE_ID
, a.ACTIVITY_DAY
, a.FAIL_TIME as a_fail_time
, b.FAIL_TIME as b_fail_time
, c.FAIL_TIME as a_fail_time
, count(*) over (partition by a.OFFICE_ID, a.ACTIVITY_DAY) as fail_count
from a
join b on a.OFFICE_ID = b.OFFICE_ID and a.ACTIVITY_DAY = b.ACTIVITY_DAY
join c on a.OFFICE_ID = c.OFFICE_ID and a.ACTIVITY_DAY = c.ACTIVITY_DAY
where a.FAIL_TIME_SSSSS between b.FAIL_TIME_SSSSS - 600 and b.FAIL_TIME_SSSSS + 600
and a.FAIL_TIME_SSSSS between c.FAIL_TIME_SSSSS - 600 and c.FAIL_TIME_SSSSS + 600
and b.FAIL_TIME_SSSSS between a.FAIL_TIME_SSSSS - 600 and a.FAIL_TIME_SSSSS + 600
and b.FAIL_TIME_SSSSS between c.FAIL_TIME_SSSSS - 600 and c.FAIL_TIME_SSSSS + 600
and c.FAIL_TIME_SSSSS between a.FAIL_TIME_SSSSS - 600 and a.FAIL_TIME_SSSSS + 600
and c.FAIL_TIME_SSSSS between b.FAIL_TIME_SSSSS - 600 and b.FAIL_TIME_SSSSS + 600
)
where fail_count >= 3
/
Примечание
- Очевидно, у меня есть жестко идентификатор клиента в подзапросах. Можно было бы избежать жесткого кодирования, но примерный запрос уже достаточно сложный.
- Этот запрос не ищет триплетов. Предоставление одного отказа для каждого из A, B и C в течение десяти минутного окна не имеет значения, сколько экземпляров каждый КЛИЕНТ происходит внутри окна. В ваших деловых правилах ничего не говорится, чтобы сказать, что это неправильно.
- Аналогичным образом, один и тот же экземпляр один КЛИЕНТ может быть сопоставлен с экземплярами других КЛИЕНТОВ в окнах . Теперь это может быть нежелательным: двойной или тройной подсчет может раздуть FAIL_COUNT. Но опять же, обработка этого будет сделать окончательный запрос более сложным.
- Представленный запрос имеет одну строку для каждой отдельной комбинации значений A, B и C FAIL_TIME. Набор результатов можно поворачивать, если вам действительно нужна строка для каждого CLIENT/FAIL_TIME.
Что тип данных FAIL_TIME? – APC