Oracle SQL функция или корзины для фильтрации данных - PullRequest
0 голосов
/ 06 октября 2018
SELECT 
     transaction
    ,date
    ,mail
    ,status
    ,ROW_NUMBER() OVER (PARTITION BY mail ORDER BY date) AS rownum
FROM table1

enter image description here

Имея вышеупомянутую таблицу и скрипт, я хочу иметь возможность фильтровать транзакции на основе наличия первых 3 строк с состоянием «сбой» дляпокажите rowid 4, если 'не удалось', если транзакции с rowid 4,5,6 потерпели неудачу - покажите 7, если также произошел сбой и т. д. Я думал о добавлении его в фрейм данных pandas, где можно запустить простую лямбда-функцию, но очень хотелось бы найтирешение только в SQL.

Ответы [ 3 ]

0 голосов
/ 06 октября 2018

Одним из вариантов является использование оконных функций.Используйте lag, чтобы получить предыдущее значение состояния (на основе указанного порядка), сравнить его со значением текущей строки и назначить группы с промежуточной суммой.Затем подсчитайте значения в каждой группе и, наконец, отфильтруйте по этому условию.

SELECT t.*
FROM
  ( SELECT t.*,
           count(*) over(PARTITION BY mail, grp) AS grp_count
   FROM
     ( SELECT t.*,
              sum(CASE
                      WHEN (prev_status IS NULL AND status='FAILED') OR 
                           (prev_status='FAILED' AND status='FAILED') THEN 0
                      ELSE 1
                  END) over(PARTITION BY mail ORDER BY "date","transaction") AS grp
      FROM
        ( SELECT t.*,
                 lag(status) over(PARTITION BY mail ORDER BY "date","transaction") AS prev_status
         FROM tbl t 
        ) t 
     ) t 
 ) t
WHERE grp_count>=4

Если вы используете версии, начинающиеся с Oracle 12c, есть опция для использования MATCH_RECOGNIZE, которая упростит это.

select *
from tbl
MATCH_RECOGNIZE (
         PARTITION BY mail
         ORDER BY "date" ,"transaction"
         ALL ROWS PER MATCH
         AFTER MATCH SKIP TO LAST FAIL
         PATTERN(fail{4,})
         DEFINE 
         fail AS (status='FAILED')
       ) MR
ORDER BY "date","transaction"
0 голосов
/ 06 октября 2018

Вы можете использовать lead() и lag() для явной проверки:

select t.*
from (select t1.*,
             lag(status, 3) over (partition by mail order by date) as status_3,
             lag(status, 3) over (partition by mail order by date) as status_2,
             lag(status, 3) over (partition by mail order by date) as status_1,
             lead(status, 1) over (partition by mail order by date) as status_3n,
             lead(status, 2) over (partition by mail order by date) as status_2n,
             lead(status, 3) over (partition by mail order by date) as status_3n
      from t
     ) t
where status = 'FAILED' and
      ( (status_3 = 'FAILED' and status_2 = 'FAILED' and status_1 = 'FAILED') or
        (status_2 = 'FAILED' and status_1 = 'FAILED' and status_1n = 'FAILED') or
        (status_1 = 'FAILED' and status_1n = 'FAILED' and status_2n = 'FAILED') or
        (status_1n = 'FAILED' and status_2n = 'FAILED and status_3n = 'FAILED')
      )

Это немного грубая сила, но я думаю, логика вполне ясна.

Вы могли быупростить логику до:

where regexp_like(status_3 || status_2 || status_1 || status || status_1n || status_2n || status3n,
                  'FAILED{4}'
                 )
0 голосов
/ 06 октября 2018

Попробуйте это:

select * from (
SELECT 
     transaction
    ,date
    ,mail
    ,status
    ,ROW_NUMBER() OVER (PARTITION BY mail ORDER BY date) AS rownum
FROM table1
WHERE status = 'FAILED' )
where mod(rownum, 3) = 1;

Ричард

...