Часто при разработке учетных систем, систем бронирования или распределения номерных фондов возникает задача: есть исходный диапазон (например, номера от 1 до 99) и набор поддиапазонов, которые нужно исключить. В языке запросов 1С задача осложняется отсутствием прямых функций для работы с интервалами, поэтому мы разберем надежный и эффективный способ реализации этой логики с помощью временных таблиц.
Для начала давайте определимся с входными данными. У нас есть две сущности: исходный диапазон и список диапазонов-исключений. Чтобы наш запрос работал универсально, представим их как временные таблицы. Предположим, что вычитаемые диапазоны не пересекаются друг с другом.
Создадим наши таблицы:
ВЫБРАТЬ
1 КАК Начало,
99 КАК Конец
ПОМЕСТИТЬ Полный
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
15 КАК Начало,
30 КАК Конец
ПОМЕСТИТЬ Исключение
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
47,
52
;
Теперь, когда данные подготовлены, перейдем к самому алгоритму вычитания.
Основная идея заключается в том, чтобы превратить задачу вычитания в задачу поиска новых границ интервалов. Нам нужно найти все «точки разрыва», которыми являются начала и концы исключаемых интервалов, скорректированные на единицу.
Разберем процесс по шагам:
ЛЕВОЕ СОЕДИНЕНИЕ для сопоставления начал и ближайших подходящих концов.Реализуем это в коде запроса:
ВЫБРАТЬ РАЗЛИЧНЫЕ
Исключение.Конец + 1 КАК Начало
ПОМЕСТИТЬ ВТ_НачалаОтрезков
ИЗ
Исключение КАК Исключение
ОБЪЕДИНИТЬ
ВЫБРАТЬ
Полный.Начало
ИЗ
Полный КАК Полный
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
Исключение.Начало - 1 КАК Конец
ПОМЕСТИТЬ ВТ_КонцыОтрезков
ИЗ
Исключение КАК Исключение
ОБЪЕДИНИТЬ
ВЫБРАТЬ РАЗЛИЧНЫЕ
Полный.Конец
ИЗ
Полный КАК Полный
;
Теперь нам осталось соединить полученные начала и концы, чтобы сформировать результирующую таблицу. Важно правильно отсечь «мусорные» интервалы, которые могут возникнуть при некорректном сопоставлении точек.
ВЫБРАТЬ
ВТ_НачалаОтрезков.Начало КАК Начало,
МИНИМУМ(ВТ_КонцыОтрезков.Конец) КАК Конец
ПОМЕСТИТЬ ВТ_НаложениеОтрезков
ИЗ
ВТ_НачалаОтрезков КАК ВТ_НачалаОтрезков
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_КонцыОтрезков КАК ВТ_КонцыОтрезков
ПО ВТ_НачалаОтрезков.Начало <= ВТ_КонцыОтрезков.Конец
СГРУППИРОВАТЬ ПО
ВТ_НачалаОтрезков.Начало
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ_НаложениеОтрезков.Начало КАК Начало,
ВТ_НаложениеОтрезков.Конец КАК Конец
ИЗ
ВТ_НаложениеОтрезков КАК ВТ_НаложениеОтрезков
ГДЕ
ВТ_НаложениеОтрезков.Начало <= ВТ_НаложениеОтрезков.Конец
УПОРЯДОЧИТЬ ПО
Начало
Рассмотренный подход имеет ряд преимуществ:
ПОМЕСТИТЬ позволяет оптимизатору запросов 1С правильно выстроить план выполнения, что важно при больших объемах данных.Для каждого на стороне сервера 1С.При работе с диапазонами всегда учитывайте граничные случаи. Важно проверять, чтобы начало диапазона всегда было меньше или равно его концу. Если в данных встречаются ситуации, когда исключаемый интервал выходит за границы основного, результат запроса может потребовать дополнительной фильтрации с помощью условия ГДЕ, как мы сделали на финальном этапе. Всегда проверяйте результат на пустых выборках — использование функций ЕСТЬNULL поможет сделать алгоритм более устойчивым.
Этот метод является классическим решением, которое можно адаптировать под практически любые задачи, где требуется манипуляция числовыми интервалами в 1С.