Разница дат MYSQL между несколькими датами в одних и тех же строках

У меня есть таблица с журналом изменений, каждая строка дает мне информацию о действиях.

Пример:

  • Билет закрыт на 2022-06-26 14:12:07.000
  • Билет открыт 28.06.2022 08:35:59.000
  • Билет закрыт на 2022-06-28 12:55:11.000
  • Билет открыт 30.06.2022 17:04:34.000

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

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

Данные из журнала изменений

Я нашел похожие проблемы, подобные этой Разница дат MySQL между двумя строками а вот макс и мин но мне нужно считать каждое изменение

Вот я думаю, что для этого нужны все данные Стол

# Созданный поле из строки нанизывать идентификатор 1 2022-06-20 13:08:26.000 положение дел Открыть Закрыто 50850 2 2022-06-20 13:16:53.000 положение дел Закрыто Открыт повторно 50850 3 2022-06-20 13:27:12.000 положение дел Открыть Закрыто 50850 4 2022-06-20 13:27:18.000 положение дел Закрыто Открыт повторно 50850 5 2022-06-20 13:37:44.000 положение дел Открыть Закрыто 50850 6 2022-06-20 13:51:15.000 положение дел Закрыто Открыт повторно 50850 7 2022-06-21 15:40:44.000 положение дел Открыть Закрыто 50850 8 2022-06-22 07:59:29.000 положение дел Закрыто Открыт повторно 50850 9 2022-06-22 08:04:59.000 положение дел Открыть Закрыто 50850 10 2022-06-22 10:58:12.000 положение дел Закрыто Открыт повторно 50850 11 2022-06-22 19:27:42.000 положение дел Открыть Закрыто 50850 12 2022-06-22 19:28:33.000 положение дел Закрыто Открыт повторно 50850 13 2022-06-22 19:29:13.000 положение дел Открыть Закрыто 50850 14 2022-06-22 19:29:27.000 положение дел Закрыто Открыт повторно 50850 15 2022-06-23 16:24:36.000 положение дел Открыть Закрыто 50850 16 2022-06-23 16:29:09.000 положение дел Закрыто Открыт повторно 50850 17 2022-06-23 16:30:37.000 положение дел Открыть Закрыто 50850 18 2022-06-23 16:33:18.000 положение дел Закрыто Открыт повторно 50850 19 2022-06-23 16:33:48.000 положение дел Открыть Закрыто 50850 20 2022-06-23 16:34:27.000 положение дел Закрыто Открыт повторно 50850 21 2022-06-23 16:34:46.000 положение дел Открыть Закрыто 50850

вы можете добавить свою структуру таблицы с примерами данных, чтобы мы могли помочь вам с запросом :)

MRonline 06.04.2023 08:54

добавляю как выглядит таблица

Bartosz Połatyński 06.04.2023 09:15
Советы, как задать хороший вопрос по языку структурированных запросов (SQL)б #5 и #3. И никаких изображений, только форматированный текст.
Akina 06.04.2023 10:05
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для
Освоение архитектуры микросервисов с Laravel: Лучшие практики, преимущества и советы для
В последние годы архитектура микросервисов приобрела популярность как способ построения масштабируемых и гибких приложений. Laravel , популярный PHP...
Как построить CRUD-приложение в Laravel
Как построить CRUD-приложение в Laravel
Laravel - это популярный PHP-фреймворк, который позволяет быстро и легко создавать веб-приложения. Одной из наиболее распространенных задач в...
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
Освоение PHP и управление базами данных: Создание собственной СУБД - часть II
В предыдущем посте мы создали функциональность вставки и чтения для нашей динамической СУБД. В этом посте мы собираемся реализовать функции обновления...
Документирование API с помощью Swagger на Springboot
Документирование API с помощью Swagger на Springboot
В предыдущей статье мы уже узнали, как создать Rest API с помощью Springboot и MySql .
Роли и разрешения пользователей без пакета Laravel 9
Роли и разрешения пользователей без пакета Laravel 9
Этот пост изначально был опубликован на techsolutionstuff.com .
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
Как установить LAMP Stack - Security 5/5 на виртуальную машину Azure Linux VM
В предыдущей статье мы завершили установку базы данных, для тех, кто не знает.
0
3
70
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы должны каким-то образом получить (логировать) строки, содержащие две метки времени, чтобы сделать некоторые различия так, как вы это делаете в настоящее время, на основе этой «другой таблицы».

Таким образом, базовой таблицей для запроса является ваша таблица журнала, предоставляющая метку времени, например. действия «открытия билета». Теперь присоединитесь к той же таблице во второй раз, чтобы получить временную метку действий «закрыть тикет». Критериями присоединения являются идентификатор тикета и отметка времени закрытия, которые должны быть минимальными, но позже открытия, а также правильный источник («открыто») и целевая статистика («закрыто»).

... в результате получается такой запрос (непроверенные и измененные имена столбцов для лучшего понимания, просто поймите идею):

SELECT ticket_id,timediff(l2_min_time,l1_time)
FROM ( SELECT l1.ticket_id,l1.time l1_time,min(l2.time) l2_min_time
    FROM log_table l1
    JOIN log_table l2
        ON  l1.ticket_id=l2.ticket_id
        AND l1.time<=l2.time
        AND l1.targetStatus = "open"
        AND l2.targetStatus = "closed"
    GROUP BY l1.ticket_id,l1.time
    ) t1

Имейте в виду, что вы работаете над перекрестным произведением «двух» потенциально больших таблиц, которые, вероятно, не оптимизированы для таких объединений. Этот запрос требует много ресурсов ЦП и/или ОЗУ и должен стать основой для хорошо настроенных индексов, прежде чем запускать его в производство.

Ответ принят как подходящий

Поскольку ваш образец changelog данных начинается с status изменения с Open на Closed, я предположил, что исходная дата и время Open должна исходить из самого билета.

В своем вопросе вы указали:

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

но number of days между 2022-06-20 13:16:53 и 2022-06-20 13:27:12, очевидно, равен 0, поэтому в этих примерах я сделал все расчеты в секундах.

Если вы делаете этот расчет только для билетов Closed (поэтому для каждого статуса closed/open есть статус reopened), то вы можете использовать простой GROUP BY:

SELECT id,
    SUM(
        CASE
            WHEN toString = 'closed' THEN TO_SECONDS(created)
            WHEN toString IN ('open', 'reopened') THEN - TO_SECONDS(created)
        END
    ) AS duration_sec
FROM (
    SELECT created, toString, id FROM changelog WHERE field = 'status'
    UNION ALL
    SELECT created, 'Open', id FROM tickets
) t
GROUP BY id;

Другой подход заключается в использовании коррелированного подзапроса для получения времени closed, а если заявка не закрыта, используйте текущую дату и время, чтобы рассчитать, как долго она была открыта:

SELECT id, SUM(TIMESTAMPDIFF(SECOND, opened, IFNULL(closed, NOW()))) AS duration_sec
FROM (
    SELECT id, created AS opened, (SELECT created FROM changelog WHERE id = t.id AND field = 'status' AND toString = 'closed' AND created > t.created ORDER BY created ASC LIMIT 1) AS closed
    FROM tickets t
    UNION ALL
    SELECT id, created AS opened, (SELECT created FROM changelog WHERE id = cl.id AND field = 'status' AND toString = 'closed' AND created > cl.created ORDER BY created ASC LIMIT 1) AS closed
    FROM changelog cl
    WHERE cl.field = 'status' AND toString IN ('reopened')
) t
GROUP BY id;

Другой подход, использующий оконную функцию LEAD() для получения значения created из следующей строки и Общие табличные выражения (CTE) для разделения запроса:

WITH ticket_status_changes AS (
    SELECT created, toString, id FROM changelog WHERE field = 'status'
    UNION ALL
    SELECT created, 'open', id FROM tickets
),
ticket_open_close AS (
    SELECT
        id, toString, created AS opened,
        IF(
            toString IN ('open', 'reopened'),
            LEAD(created) OVER (PARTITION BY id ORDER BY created ASC),
            NULL
        ) AS closed
    FROM ticket_status_changes
)
SELECT id, SUM(TIMESTAMPDIFF(SECOND, opened, IFNULL(closed, NOW()))) AS duration_sec
FROM ticket_open_close
WHERE toString IN ('open', 'reopened')
GROUP BY id;

Другие вопросы по теме