SQL - скользящая сумма с перезагрузками на основе будущих и текущих критериев - PullRequest
0 голосов
/ 01 февраля 2019

У меня есть таблица пар время / продолжительность. Время указано с 15-минутными интервалами с возможными промежутками.Длительности представляют собой значения от 5 минут до 15 минут:

slot_ts             | duration
------------------- |----------
2019-01-28 07:45:00 | 00:05:00
2019-01-28 08:00:00 | 00:10:00
2019-01-28 08:15:00 | 00:10:00
2019-01-28 08:30:00 | 00:10:00
2019-01-28 08:45:00 | 00:15:00
2019-01-28 09:30:00 | 00:15:00
2019-01-28 09:45:00 | 00:15:00
2019-01-28 10:00:00 | 00:15:00
2019-01-28 10:15:00 | 00:15:00
2019-01-28 10:30:00 | 00:15:00
2019-01-28 11:00:00 | 00:15:00
2019-01-28 11:15:00 | 00:15:00
2019-01-28 11:30:00 | 00:10:00
2019-01-28 11:45:00 | 00:15:00
2019-01-28 12:00:00 | 00:15:00

Обратите внимание на промежутки времени с 8:45 до 9:30.И с 10:30 до 11:00.

Концепция заключается в каждом отдельном интервале (который охватывает 15-минутный период), показанная продолжительность представляет собой доступное время, все еще находящееся в этом интервале.Так, например, в слоте 7:45 есть 5 минут, которые еще доступны в этом слоте (т. Е. 10 минут израсходованы).Если 15-минутный интервал времени отсутствует, это означает, что в этом интервале нет свободного времени.Так, например, для слотов 9:00, 9:15, 10:45 нет доступного времени.

Я хочу сгенерировать продолжительность работы для каждого временного интервала, где продолжительность работы сбрасывается на основе некоторыхКритерии.

Если какой-либо из этих критериев удовлетворен, продолжительность работы должна быть сброшена:

  1. Между слотами есть промежуток (например, 9:30 будеттребуется сброс)
  2. Следующая длительность составляет менее 15 минут (но включите эту следующую длительность в промежуточную сумму до сброса) - это в значительной степени означает, что при отсутствии разрыва длительность выполнения можетпродолжить для всех интервалов между текущей продолжительностью и продолжительностью, не равной 15 минутам включительно .Таким образом, продолжительность пробежки в 8:00 составит 20 минут, поскольку в 8:00 - 10 минут, а в 8:15 - 10 минут.

Изображения лучше, чем слова, так что вот пример того, что яm ищет:

slot_ts             | duration | running_duration
------------------- |----------|------------------
2019-01-28 07:45:00 | 00:05:00 | 00:15:00
2019-01-28 08:00:00 | 00:10:00 | 00:20:00
2019-01-28 08:15:00 | 00:10:00 | 00:20:00
2019-01-28 08:30:00 | 00:10:00 | 00:25:00
2019-01-28 08:45:00 | 00:15:00 | 00:15:00
2019-01-28 09:30:00 | 00:15:00 | 01:15:00
2019-01-28 09:45:00 | 00:15:00 | 01:00:00
2019-01-28 10:00:00 | 00:15:00 | 00:45:00
2019-01-28 10:15:00 | 00:15:00 | 00:30:00
2019-01-28 10:30:00 | 00:15:00 | 00:15:00
2019-01-28 11:00:00 | 00:15:00 | 00:40:00
2019-01-28 11:15:00 | 00:15:00 | 00:25:00
2019-01-28 11:30:00 | 00:10:00 | 00:10:00
2019-01-28 11:45:00 | 00:15:00 | 00:30:00
2019-01-28 12:00:00 | 00:15:00 | 00:15:00

Обратите внимание, что в моем примере из реальной жизни эта таблица будет хранить эти значения «доступных слотов» в интервале 6 месяцев вместо промежутка времени от 7:45 до полудня Iв этом примере

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

Вот мой существующий запрос, Вы можете сделать лучше ??

SELECT
    slot_ts,
    duration,
    COALESCE(
    (
        SELECT  SUM(duration)
        FROM    available_slots
        WHERE   slot_ts >= x.slot_ts 
            AND slot_ts <= 
                (
                    SELECT slot_ts AS last_ts
                    FROM
                    (
                        SELECT  *,
                                NOT COALESCE(lead(slot_ts) OVER (ORDER BY slot_ts) = slot_ts + '00:15:00', FALSE) AS cur_row_stop,
                                NOT COALESCE(lead(slot_ts) OVER (ORDER BY slot_ts) = slot_ts + '00:15:00', FALSE) OR duration < '00:15:00' AS prev_row_stop
                        FROM    available_slots
                    ) z
                    WHERE (cur_row_stop AND slot_ts = x.slot_ts) OR (prev_row_stop AND slot_ts > x.slot_ts)
                    ORDER BY slot_ts LIMIT 1        
                )
        ), duration) AS running_duration
FROM available_slots AS x
ORDER BY slot_ts ASC;

Вот sql fiddle вышеуказанной схемы таблицы и запроса.

...