SQL-根据将来和当前条件进行重置的滚动总和

时间:2019-02-01 14:51:55

标签: sql postgresql performance subquery window-functions

我有一个时间/持续时间对表。时间间隔为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分钟。

图片胜于文字,所以这是我所寻找的示例:

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到正午跨度

有一个有效的查询,但它使用了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

0 个答案:

没有答案