Как найти пересечения интервалов времени в запросе 1С и исключить зеркальные дубли

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При составлении графиков работы, планировании расписаний смен или контроле занятости оборудования часто возникает задача проверки наложения временных интервалов. При попытке соединить таблицу интервалов саму с собой разработчики регулярно сталкиваются с двумя сложностями: некорректным определением самого факта пересечения через оператор МЕЖДУ и получением задвоенных «зеркальных» пар (например, Смена 1 пересекается со Сменой 2, и одновременно Смена 2 пересекается со Сменой 1). Разберем по шагам, как правильно составить запрос для поиска пересечений и исключить появление дублирующих строк.

Анализ классических ошибок при определении пересечения интервалов

Проанализируем распространенную ошибку: использование проверки вхождения границ через условие МЕЖДУ (или BETWEEN):


И (ТаблицаИнтервалов.ВремяНачалаИнтервала МЕЖДУ ТаблицаИнтервалов1.ВремяНачалаИнтервала И ТаблицаИнтервалов1.ВремяОкончанияИнтервала
    ИЛИ ТаблицаИнтервалов.ВремяОкончанияИнтервала МЕЖДУ ТаблицаИнтервалов1.ВремяНачалаИнтервала И ТаблицаИнтервалов1.ВремяОкончанияИнтервала)

Такое условие не сработает, если один интервал полностью охватывает другой (например, смена А длится с 08:00 до 20:00, а смена Б — с 10:00 до 12:00). В этом случае ни начало, ни окончание смены А не лежат внутри диапазона 10:00–12:00, и запрос пропустит наложение.

Математически корректное условие: два интервала пересекаются тогда и только тогда, когда начало первого меньше окончания второго, а начало второго меньше окончания первого. Для полуоткрытых интервалов условие соединения выглядит следующим образом:


ПО Интервал1.ВремяНачала < Интервал2.ВремяОкончания
    И Интервал2.ВремяНачала < Интервал1.ВремяОкончания

Если смежные границы (например, стык в стык: окончание в 10:00 и начало следующего в 10:00) не считаются наложением, необходимо использовать строгое неравенство < и >.

Решение проблемы зеркальных дублей в запросе

Когда мы соединяем таблицу саму с собой с условием НЕ Таблица1.Смена = Таблица2.Смена, платформа находит пару (Смена 1, Смена 2) и симметричную ей пару (Смена 2, Смена 1). Чтобы избавиться от перевернутых дублей без ресурсоемких группировок, зададим строгое отношение порядка между строками.

Разберем готовый текст запроса, где во временную таблицу помещаются интервалы смен и выполняется поиск уникальных пар пересечений:


ВЫБРАТЬ
    СменыПериодыСмены.Ссылка КАК Смена,
    СменыПериодыСмены.НомерСтроки КАК НомерСтрокиИнтервала,
    СменыПериодыСмены.ВремяНачала КАК ВремяНачалаИнтервала,
    СменыПериодыСмены.ВремяОкончания КАК ВремяОкончанияИнтервала
ПОМЕСТИТЬ ВТ_Интервалы
ИЗ
    Справочник.Смены.ПериодыСмены КАК СменыПериодыСмены
ГДЕ
    СменыПериодыСмены.Ссылка В(&СписокСмен)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    Т1.Смена КАК Смена1,
    Т1.НомерСтрокиИнтервала КАК НомерСтроки1,
    Т1.ВремяНачалаИнтервала КАК ВремяНачала1,
    Т1.ВремяОкончанияИнтервала КАК ВремяОкончания1,
    Т2.Смена КАК Смена2,
    Т2.НомерСтрокиИнтервала КАК НомерСтроки2,
    Т2.ВремяНачалаИнтервала КАК ВремяНачала2,
    Т2.ВремяОкончанияИнтервала КАК ВремяОкончания2,
    // Вычисляем фактические границы пересечения
    ВЫБОР
        КОГДА Т1.ВремяНачалаИнтервала > Т2.ВремяНачалаИнтервала
            ТОГДА Т1.ВремяНачалаИнтервала
        ИНАЧЕ Т2.ВремяНачалаИнтервала
    КОНЕЦ КАК ВремяНачалаПересечения,
    ВЫБОР
        КОГДА Т1.ВремяОкончанияИнтервала < Т2.ВремяОкончанияИнтервала
            ТОГДА Т1.ВремяОкончанияИнтервала
        ИНАЧЕ Т2.ВремяОкончанияИнтервала
    КОНЕЦ КАК ВремяОкончанияПересечения
ИЗ
    ВТ_Интервалы КАК Т1
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Интервалы КАК Т2
        // Исключаем сравнение интервала с самим собой и убираем зеркальные пары
        ПО (Т1.Смена < Т2.Смена
            ИЛИ (Т1.Смена = Т2.Смена И Т1.НомерСтрокиИнтервала < Т2.НомерСтрокиИнтервала))
            // Корректное условие наложения интервалов
            И Т1.ВремяНачалаИнтервала < Т2.ВремяОкончанияИнтервала
            И Т2.ВремяНачалаИнтервала < Т1.ВремяОкончанияИнтервала

Как работает строгое упорядочивание ключей

Рассмотрим подробнее условие связи (Т1.Смена < Т2.Смена ИЛИ (Т1.Смена = Т2.Смена И Т1.НомерСтрокиИнтервала < Т2.НомерСтрокиИнтервала)):

  1. Исключение рефлексивности: Строка никогда не соединится сама с собой, так как условие строгого неравенства для одинаковых строк вернет ложь.
  2. Исключение симметричности: Для двух разных записей А и Б условие выполнится только в одном направлении (где ключ записи А меньше ключа записи Б). В обратную сторону условие отсечет пару, предотвращая появление задвоенных строк вида 2–1.
  3. Поддержка интервалов внутри одной смены: Вторая часть условия (Т1.Смена = Т2.Смена И Т1.НомерСтрокиИнтервала < Т2.НомерСтрокиИнтервала) позволяет находить внутренние пересечения строк табличной части в рамках одного и того же документа или элемента справочника.

Особенности интервалов с переходом через полночь

Если в реквизитах времени дата зафиксирована как служебная (например, 01.01.0001), интервалы с переходом через полночь (например, 22:15 – 02:15) содержат значение времени окончания меньше, чем время начала. В таких ситуациях прямое сравнение в запросе отработает некорректно.

Для корректного сопоставления выполним предварительную нормализацию таблицы интервалов одним из двух подходов:

  1. Смещение суток: Если ВремяОкончания < ВремяНачала, прибавляем к времени окончания один день с помощью функции ДОБАВИТЬКДАТЕ(ВремяОкончания, ДЕНЬ, 1).
  2. Разбиение на два отрезка: Через конструкцию ОБЪЕДИНИТЬ ВСЕ разделяем ночной период на две строки: от времени начала до 23:59:59 и от 00:00:00 до времени окончания.

Применение математически точных условий наложения и строгого порядка ключевых полей в секции ПО позволяет получить очищенный список пересекающихся интервалов без использования громоздких группировок и дополнительной программной постобработки в коде 1С.

← На главную