Минуты между датами, когда несколько записей - PullRequest
0 голосов
/ 26 марта 2019

В таблице «Audit» есть поля id, old_status, new_status и updated_at.Статус содержит значения Open, On Hold и Closed.Я хочу определить, как долго аудит находился в режиме ожидания, простой расчет:

SELECT Datediff(minute, (SELECT Min(changed_at) 
                         FROM   audit 
                         WHERE  id = 123 
                                AND new_status = 'On Hold'), 
       (SELECT Max(changed_at) 
        FROM   audit 
        WHERE  id = 123 
               AND old_status = 
                   'On Hold')) 

Но теперь у меня есть запись аудита, которая была помещена в режим ожидания несколько раз.Вышеприведенный расчет показывает общее время между первым переходом в режим ожидания и последним выходом из режима ожидания, но он не отражает фактическое время ожидания.

Есть лизапрос, который вернул бы это фактическое время?

Ответы [ 2 ]

0 голосов
/ 26 марта 2019

В ответе ниже я предполагаю, что исходное / заданное по умолчанию состояние записи - «Открыть».Я также предполагаю, что ваша версия SQL Server имеет функции LEAD / LAG.

Допустим, у вас есть информация о 3 записях.Все 3 записи начинаются со статуса «Открыто».

  • Для Записи 1 состояние менялось 4 раза:
    • В 8:00 оно было изменено с Открыто на Удержание..
    • В 9:00 оно было изменено с «Удержание» на «Открытие». * 10:00
    • С 10:00 оно было снова переведено на «Удержание».: 00.
  • Для записи 2 статус был изменен дважды:
    • В 8:00 он был изменен с «Открыто» на «Удержание».
    • В 9:00 оно было изменено на Закрыто.
  • Запись 3 имеет только одно изменение:
    • В 8:00 оно было изменено с Открытого на Удержание(имеется в виду, что текущий статус находится на удержании).

Вот данные в табличной форме:

+----+------------+------------+------------------+
| id | old_status | new_status |    changed_at    |
+----+------------+------------+------------------+
|  1 | Open       | On Hold    | 2019-03-26 08:00 |
|  1 | On Hold    | Open       | 2019-03-26 09:00 |
|  1 | Open       | On Hold    | 2019-03-26 10:00 |
|  1 | On Hold    | Closed     | 2019-03-26 11:00 |
|  2 | Open       | On Hold    | 2019-03-26 08:00 |
|  2 | On Hold    | Closed     | 2019-03-26 09:00 |
|  3 | Open       | On Hold    | 2019-03-26 08:00 |
+----+------------+------------+------------------+

Из данных и моего пониманияваша проблема, вы хотите, чтобы общее время записи было приостановлено.Таким образом, для 3 вышеуказанных записей:

  • Запись 1 была приостановлена ​​в общей сложности 2 часа / 120 минут: 1 час с 8 до 9, затем еще один час с 10 до 11.
  • Запись 2 была приостановлена ​​всего на 1 час: с 8 до 9.
  • Для записи 3 неясно, каковы ваши ожидаемые результаты: будут ли результаты с 8:00 (когда они были помещены наудерживать) до текущей даты / времени?Или вы хотите исключить это из своих результатов?

Чтобы начать атаку на проблему, сначала вы можете использовать функции WINDOW, чтобы просмотреть связанные результаты.Я использовал LAG.

Сначала вы можете использовать LAG, чтобы выяснить, где произошло последнее изменение (для записи):

SELECT 
    [id], 
    old_status,
    new_status,
    changed_at,
    prev_changed = LAG(changed_at) OVER
    (
        PARTITION BY [id]
        ORDER BY [id], changed_at
    )
FROM audit_records

Это даст вам следующие результаты:

+----+------------+------------+------------------+------------------+
| id | old_status | new_status |    changed_at    |   prev_changed   |
+----+------------+------------+------------------+------------------+
|  1 | Open       | On Hold    | 2019-03-26 08:00 | NULL             |
|  1 | On Hold    | Open       | 2019-03-26 09:00 | 2019-03-26 08:00 |
|  1 | Open       | On Hold    | 2019-03-26 10:00 | 2019-03-26 09:00 |
|  1 | On Hold    | Closed     | 2019-03-26 11:00 | 2019-03-26 10:00 |
|  2 | Open       | On Hold    | 2019-03-26 08:00 | NULL             |
|  2 | On Hold    | Closed     | 2019-03-26 09:00 | 2019-03-26 08:00 |
|  3 | Open       | On Hold    | 2019-03-26 08:00 | NULL             |
+----+------------+------------+------------------+------------------+

Обратите внимание на записи со значением NULL: это записи, которые не имеют изменений до изменения .Таким образом, для Записи 1 изменение с Открытого на Удержание равно нулю, поскольку это было первое изменение.

Теперь вы можете заключить это в CTE и рассчитать количество минут:

WITH 
    audit_records_lead_lag([id], old_status, new_status, changed_at, prev_changed) AS
    (
        SELECT 
            [id], 
            old_status,
            new_status,
            changed_at,
            prev_changed = LAG(changed_at) OVER
            (
                PARTITION BY [id]
                ORDER BY [id], changed_at
            )
        FROM audit_records
    )
SELECT 
    [id], 
    minutes_in_hold = SUM(DATEDIFF(MINUTE, prev_changed, changed_at))
FROM audit_records_lead_lag
WHERE
    old_status = 'On Hold'
    AND prev_changed IS NOT NULL
GROUP BY [id]

, который дает следующие результаты:

+----+-----------------+
| id | minutes_in_hold |
+----+-----------------+
|  1 |             120 |
|  2 |              60 |
+----+-----------------+
0 голосов
/ 26 марта 2019

Присоединение таблицы к себе при условии, что левая сторона СОЕДИНЕНИЯ находится в состоянии «Удержание», а правая сторона является ТОП-1 по времени после левой стороны, НЕ «Удерживается» и имеет то же самое ID как левая сторона.

Исходя из этого, ваш запрос просто получает DATEDIFF между левой записью и правой записью и SUMs, которые DATEDIFF, группируя по ID.

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