В практике разработки на платформе 1С часто возникает задача проверки наложения временных интервалов. Это может быть проверка пересечения графиков отпусков, наложение больничных листов или поиск конфликтующих записей в регистрах сведений. Основная сложность заключается не только в самой формуле пересечения, но и в том, что при соединении таблицы самой с собой (self-join) система выдает «зеркальные» дубли: пары Документ1-Документ2 и Документ2-Документ1. Рассмотрим подробнее, как составить эффективный запрос, который решит обе эти проблемы.
Когда мы пытаемся найти пересечения в рамках одной таблицы, мы обычно используем внутреннее соединение этой таблицы с ее копией по определенному условию (например, по сотруднику). Если условие пересечения выполняется для двух разных документов, запрос вернет две строки, так как для системы запись А пересекается с записью Б, а запись Б — с записью А.
Для того чтобы в итоговой выборке осталась только одна уникальная пара, проанализируем ситуацию с использованием сравнения ссылок. В языке запросов 1С ссылки можно сравнивать операторами «больше» или «меньше». Это сравнение происходит по внутреннему идентификатору (GUID). Добавив условие ТабДокументы.Ссылка < ТабДокументы1.Ссылка, мы гарантируем, что каждая пара встретится в результате только один раз.
Многие разработчики используют громоздкие конструкции с оператором МЕЖДУ и множеством условий ИЛИ, чтобы поймать все варианты наложения (начало одного периода внутри другого, окончание внутри другого, полное поглощение и т.д.). Однако существует максимально простая математическая формула, которая покрывает 100% случаев пересечения.
Разберем по шагам логику: два периода [S1, E1] и [S2, E2] пересекаются тогда и только тогда, когда начало первого периода меньше или равно концу второго, И начало второго периода меньше или равно концу первого.
Запишем это в виде условия запроса:
| ПО ТабДокументы.Сотрудник = ТабДокументы1.Сотрудник
| И ТабДокументы.ДатаНачала <= ТабДокументы1.ДатаОкончания
| И ТабДокументы1.ДатаНачала <= ТабДокументы.ДатаОкончания
| И ТабДокументы.ДокументСсылка < ТабДокументы1.ДокументСсылка
Это условие является наиболее производительным и коротким. Оно автоматически учитывает случаи, когда один период полностью поглощает другой или когда они совпадают до секунды.
Если данные находятся во временной таблице и у них нет уникальных ссылок (например, это строки таблицы значений), посмотрим на пример использования функции АВТОНОМЕРЗАПИСИ(). Этот метод позволяет пронумеровать строки и использовать этот номер для исключения дублей, аналогично сравнению ссылок.
Сначала подготовим временную таблицу:
ВЫБРАТЬ
Т.Сотрудник КАК Сотрудник,
Т.ДатаНачала КАК ДатаНачала,
Т.ДатаОкончания КАК ДатаОкончания,
Т.Ссылка КАК Ссылка,
АВТОНОМЕРЗАПИСИ() КАК НомерСтроки
ПОМЕСТИТЬ ВТ_Данные
ИЗ
&ВходящаяТаблица КАК Т
;
Затем выполним соединение:
ВЫБРАТЬ
Т1.Ссылка КАК Документ1,
Т2.Ссылка КАК Документ2,
Т1.Сотрудник КАК Сотрудник
ИЗ
ВТ_Данные КАК Т1
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Данные КАК Т2
ПО Т1.Сотрудник = Т2.Сотрудник
И Т1.ДатаНачала <= Т2.ДатаОкончания
И Т2.ДатаНачала <= Т1.ДатаОкончания
И Т1.НомерСтроки < Т2.НомерСтроки
Выясним причину, по которой иногда запрос может находить лишние пересечения. В 1С время хранится с точностью до секунды. Если один документ заканчивается в 23:59:59, а следующий начинается в 00:00:00 следующего дня, пересечения нет. Однако, если бизнес-логика предполагает, что документы не могут «касаться» друг друга краями (например, один сотрудник не может уволиться и приняться в одну и ту же секунду), следует использовать строгие неравенства < и > вместо <= и >=.
Также важно учитывать пустые даты. В некоторых конфигурациях пустая дата окончания означает «по настоящее время». Если ваш запрос может столкнуться с такими данными, проанализируем ситуацию и добавим обработку через ВЫБОР:
| ВЫБОР
| КОГДА Таб.ДатаОкончания = ДАТАВРЕМЯ(1, 1, 1)
| ТОГДА ДАТАВРЕМЯ(3999, 12, 31)
| ИНАЧЕ Таб.ДатаОкончания
| КОНЕЦ
При работе с большими объемами данных в ВТ_Данные (более 1000 записей), поиск пересечений методом «каждый с каждым» может существенно замедлить работу системы. Чтобы этого избежать, выполним следующие рекомендации:
Сотрудник. Если сотрудников много, а документов мало — это спасет ситуацию. Используйте конструкцию ИНДЕКСИРОВАТЬ ПО при создании временной таблицы.Таким образом, комбинируя универсальную формулу пересечения и сравнение ссылок, мы получаем надежный и быстрый инструмент для анализа временных интервалов в 1С.