У меня есть следующее определение таблицы с именем таблицы "JOBS" и образец данных, как показано ниже:

| job_name |   created_on   | result |
| -------- | -------------  |--------
|    x     |  2021-01-20    | fail   |<-
|    y     |  2021-01-01    | success|
|    y     |  2021-01-02    | success|
|    x     |  2021-01-22    | fail   |<-
|    z     |  2021-03-15    | fail   |<-
|    z     |  2021-03-11    | success|
|    z     |  2021-03-16    | fail   |<-
|    x     |  2021-01-18    | fail   |
|    z     |  2021-01-03    | fail   |
|    x     |  2021-01-19    | success|

Мне нужно найти недавние последовательные задания, которые не работают подряд N раз, отсортированные по убыванию даты создания. Это применимо для каждой группы заданий в таблице.

Например. если N = 3, мне нужно найти имена вакансий с тремя недавними сбоями подряд с датой в порядке убывания (последние даты).

Для приведенной выше таблицы результат должен быть

| job_name |   created_on   | result|
| -------- | -------------- |
|    x     |  2021-01-22    | fail  |
|    x     |  2021-01-20    | fail  |
|    z     |  2021-03-16    | fail  |
|    z     |  2021-03-15    | fail  |

В приведенном выше случае N = 2 (т. Е. Количество последовательных сбоев заданий для каждой группы заданий)

Я пробовал использовать lag, lead, partition by, но не смог найти точного решения.

Я пробовал ниже запрос для N = 2.

select distinct(m.job_name)
    from (select t.*,
                 lag(result) over (partition by job_name order by created_on) as prev_result,
                 lead(result) over (partition by job_name order by created_on) as next_result
          from JOBS AS t
          order by created_on DESC
         ) m
    where result = 'fail' and
          'fail' in (prev_result, next_result)
    order by m.job_name;
0
Prasad 6 Июл 2021 в 16:08

4 ответа

Лучший ответ

Проблему можно разделить на три части и решать постепенно.

1 - Получить самые последние даты успешных результатов для каждого job_name, чтобы можно было получить задания после этих дат.

SELECT j2.job_name, max(j2.created_on) mdate 
FROM jobs j2 
WHERE j2.result = 'success' 
GROUP BY j2.job_name

2 - Получить все строки со статусом "ошибка", у которых created_by стоит после последнего успешного задания.

WITH last_success_date AS (
  SELECT j2.job_name, max(j2.created_on) mdate FROM jobs j2
    WHERE j2.result = 'success' 
    GROUP BY j2.job_name
) 
SELECT j.* FROM jobs j
LEFT JOIN last_success_date lsd ON j.job_name = lsd.job_name
WHERE j.result = 'fail' AND j.created_on > lsd.mdate

3- Получайте только те результаты, которые имеют более n последовательных неудачных результатов

WITH failed_jobs AS (
  WITH last_success_date AS (
    SELECT j2.job_name, max(j2.created_on) mdate FROM jobs j2
      WHERE j2.result = 'success' 
      GROUP BY j2.job_name
  ) 
  SELECT j.* FROM jobs j
  LEFT JOIN last_success_date lsd ON j.job_name = lsd.job_name
  WHERE j.result = 'fail' AND j.created_on > lsd.mdate
) 
SELECT fj.* FROM failed_jobs fj
LEFT JOIN (
  SELECT fj2.job_name, count(fj2.id) fail_count FROM failed_jobs fj2
  GROUP BY  fj2.job_name
) AS with_counts on with_counts.job_name = fj.job_name 
WHERE fail_count >= 2 ORDER BY fj.created_on DESC

В примере выше я использовал n=2.
ссылка на скрипт базы данных

0
afzalex 6 Июл 2021 в 23:30

Этот запрос возвращает только две последние подряд строки с ошибкой результата для каждого задания:

В первом запросе "jobs_fail_groups" я помечаю ряды последовательных заданий с одинаковым результатом числом (каждая группа с вычисленным числом).

Затем во втором запросе "jobs_fail_groups_selected" я GROUP BY job_name, grupo выбираю только строки с результатом 'fail' и группы с count (*)> = 2.

В третьем запросе «результат» я ПРИСОЕДИНЯЮСЬ к предыдущим запросам ИСПОЛЬЗУЯ имя_задания и группу и вычисляю номер строки для каждого задания.

Наконец, я получаю первые два ряда каждой группы.

WITH jobs_fail_groups AS (SELECT  
                                 *,
       
                                 ROW_NUMBER() OVER (ORDER BY job_name, created_on DESC) - 
                                      ROW_NUMBER() OVER (PARTITION BY job_name, result ORDER BY job_name, created_on DESC) AS grupo
           
                             FROM jobs
                             ORDER BY job_name, created_on DESC),
                             
     jobs_fail_groups_selected AS (
                          SELECT job_name, grupo, count(*)
                          FROM jobs_fail_groups
                          WHERE result = 'fail'
                          GROUP BY job_name, grupo
                          HAVING count(*) >= 2),
                          
     result AS (SELECT
                       ROW_NUMBER() OVER (PARTITION BY job_name ORDER BY job_name, created_on DESC) AS `order`,
                       jfg.*
                FROM jobs_fail_groups jfg
                INNER JOIN jobs_fail_groups_selected jfgs USING (job_name, grupo))

SELECT r.job_name, r.created_on, r.result
FROM result r
WHERE `order` <= 2;

Этот запрос имеет некоторое сходство с некоторыми другими запросами, но не полностью то же самое.

0
nachospiu 7 Июл 2021 в 22:02
WITH 
cte1 AS ( SELECT *,
                 SUM(result = 'success') OVER (PARTITION BY job_name ORDER BY created_on) grp
          FROM jobs ),
cte2 AS ( SELECT job_name, grp, COUNT(*) cnt
          FROM cte1
          WHERE result = 'fail'
          GROUP BY job_name, grp
          HAVING cnt >= @N )
SELECT cte1.*
FROM cte1
JOIN cte2 USING (job_name, grp)
WHERE cte1.result = 'fail';

скрипка с некоторыми пояснениями.

0
Akina 7 Июл 2021 в 04:57

Вы можете сделать это с помощью коррелированного подзапроса. Предполагая, что успех и неудача - единственные значения:

select t.*
from t
where t.created_on > all (select t2.created_on
                          from t t2
                          where t2.job_name = t.job_name and
                                t2.result <> 'fail'
                         );

Альтернативный вариант использования оконных функций дает максимальное значение created_on для "успеха" и использует его для фильтрации:

select t.*
from (select t.*,
             max(case when result = 'success' then created_on end) over (partition by job_name) as max_success_created_on
      from t
     ) t
where created_on > max_success_created_on or max_success_created_on is null;

Вот скрипка db <>.

0
Gordon Linoff 6 Июл 2021 в 15:40