Комментарии 6
Хрень какая-то. Вы как задачу ставите?
Если каких-то выписок нет, нужно запросить их у клиента.
А что дают ваши запросы? только нумер клиента, которого надо трясти.
Где, спрашивается, тот самый список ИХ ? По формулировке задачи - список диапазонов дат, за которые клиент должен предоставить выписки. Или "моё дело сказать, что всё плохо, а что именно - разбирайтесь сами"? ну-ну...
Расскажу о стандартном подходе с поиском разрывов в истории через оконные функции lead, lag и подходе с использованием типа данных daterange (datemultirange).
Надо было ещё рассмотреть (вот уж на самом деле стандартный) IN-OUT. Он, кстати, даёт именно список разрывов. Ну и до кучи - рекурсивный CTE с накоплением интервала.
Добрый день!
Если расскажите про IN-OUT, буду благодарен. Загуглил, не нашел.
Если вы про операторы in, out, то чтобы сравнивать, вам сначала нужно собрать диапазон, а поскольку записей с датами произвольное количество, получается мультидиапазон, datemultirange. И функции сравнения интервалов для datemultirange как раз <@
https://postgrespro.ru/docs/postgresql/14/functions-range
---
В теории можно придумать, как вы писали, рекурсию.
Как вариант, через lead искать следующую запись, пока записи не закончатся. Или делать вычитание из искомого диапазона каждой записи.
Но, опять же, если брать рекурсию, непонятно, чем это в части сложности будет отличаться от обычного lead/lag?
---
Про условие поиск конкретных интервалов описал в ограничениях. Опустил этот пункт для упрощения статьи, чтобы сравнить сами подходы.
---
В общем, если есть примеры или ссылки, буду благодарен :)
Сам додумался до таких вариантов только.
Варианты с циклом через T-SQL не рассматривал, своими процедурами и т.п.
IN-OUT делает следующее. Сперва он собирает в единый массив все временнЫе точки и добавляет каждой "вес" - плюс единица для начала диапазона и минус единица для его конца. Затем считается кумулятивная сумма весов по возрастанию времени. Если она нулевая - то это конечная точка объединённого диапазона, а её LEAD соответственно конец "дырки" и начало следующего объединённого диапазона.
Рекурсивно - все записи нумеруются в порядке возрастания начала диапазона и затем рекурсивно обрабатываются в этом порядке. При этом к каждой записи добавляется поле текущего конца диапазона - если он меньше, чем в текущей обрабатываемой записи, берётся дата из записи, иначе остаётся дата из CTE. Затем отбираем записи, где начало получилось больше текущего из CTE - интервал от текущего до начала и есть дырки.
Подумал над вашим комментарием, придумал еще способ:
Можно сделать рекурсивное CTE, в нем на основе условий in в искомом интервале собирать второй интервал в отдельное поле. Если интервал текущей записи внутри искомого, добавляем её ко второму интервалу.
А после, уже в основном запросе, вычесть из собранного в рекурсивном CTE интервала искомый и получить разрывы.
Но звучит как будто жестко в плане написания) но можно попробовать
Использование Daterange для поиска разрывов истории записей SCD2