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

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

При разработке систем планирования рабочего времени, графиков сменности или систем учета фактической работы часто возникает задача анализа пересечений. Представим ситуацию: несколько сотрудников работают в разное время, их смены накладываются друг на друга, и нам необходимо получить «чистые» временные интервалы с указанием списка всех людей, работающих в каждый конкретный момент. В этой статье мы подробно разберем, как решить эту задачу с помощью механизмов платформы 1С:Предприятие 8.

Постановка задачи и логика решения

Допустим, у нас есть исходная таблица, где для каждого Сотрудник указаны НачСмены и КонСмены. Наша цель — разбить весь рабочий день на минимальные (элементарные) отрезки времени, внутри которых состав работающих сотрудников не меняется. Проблема стандартного соединения «каждый с каждым» заключается в том, что оно порождает огромное количество дублей и некорректных наложений. Мы воспользуемся проверенным алгоритмом, состоящим из трех последовательных этапов.

Этап 1: Формирование таблицы уникальных временных меток

Для начала нам нужно собрать все «границы» времени — все моменты начала и все моменты окончания смен всех сотрудников. Эти точки станут границами наших будущих элементарных интервалов. Разберем, как это сделать в запросе. Сначала мы помещаем исходную таблицу значений во временную таблицу ВТ_ТабЗнач, а затем объединяем колонки начала и окончания в один список.


ВЫБРАТЬ
    ТЗ.НачСмены КАК Период
ПОМЕСТИТЬ ВТ_ВсеТочки
ИЗ
    ВТ_ТабЗнач КАК ТЗ

ОБЪЕДИНИТЬ

ВЫБРАТЬ
    ТЗ.КонСмены
ИЗ
    ВТ_ТабЗнач КАК ТЗ
;

Важно помнить, что использование оператора ОБЪЕДИНИТЬ (без слова ВСЕ) автоматически выполняет группировку и оставляет только уникальные значения времени. Таким образом, мы получаем упорядоченную «шкалу» всех событий дня.

Этап 2: Создание элементарных интервалов

Теперь, когда у нас есть все точки на временной оси, нам нужно превратить их в отрезки. Отрезок — это пара «Текущая точка» и «Следующая за ней точка». Чтобы реализовать это в языке запросов 1С, мы применим левое соединение таблицы ВТ_ВсеТочки саму с собой по условию «время начала меньше времени окончания».

Проанализируем этот запрос подробнее:


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

В данном фрагменте кода мы для каждой временной метки ищем минимальную метку, которая больше текущей. Это гарантирует, что между ПериодНач и ПериодКон не попадет ни одна другая точка смены. Мы получили набор непересекающихся «кирпичиков» времени, из которых состоит рабочий день.

Этап 3: Сопоставление интервалов с сотрудниками

На заключительном этапе нам нужно понять, кто из сотрудников работал внутри каждого найденного элементарного интервала. Для этого мы соединяем наши интервалы с исходной таблицей ВТ_ТабЗнач по условию пересечения периодов.

Рассмотрим условие соединения. Чтобы избежать проблем с «лишними секундами», о которых часто упоминают разработчики, используем строгую проверку вхождения интервала. Если элементарный интервал [ПериодНач, ПериодКон] полностью лежит внутри смены сотрудника [НачСмены, КонСмены], значит, этот сотрудник в это время работал.


ВЫБРАТЬ
    Интервалы.ПериодНач КАК НачИнтервала,
    Интервалы.ПериодКон КАК КонИнтервала,
    ТЗ.Сотрудник КАК Сотрудник
ИЗ
    ВТ_ЭлементарныеИнтервалы КАК Интервалы
ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ТабЗнач КАК ТЗ
    ПО ТЗ.НачСмены <= Интервалы.ПериодНач
    И ТЗ.КонСмены >= Интервалы.ПериодКон
УПОРЯДОЧИТЬ ПО
    НачИнтервала
;

Важный момент: использование условий <= и >= здесь корректно, так как мы проверяем попадание целого интервала внутрь другого. Поскольку границы интервалов были сформированы из всех возможных точек начала и конца, ситуация, когда смена сотрудника начинается или заканчивается внутри элементарного интервала, физически невозможна.

Визуализация результата через СКД

После выполнения запроса мы получим таблицу, где один и тот же временной интервал может повторяться несколько раз (по количеству сотрудников). Чтобы привести это к виду «Один интервал — Список сотрудников через запятую», идеально подходит Система компоновки данных (СКД).

Разберем шаги настройки отчета:

  1. Добавим наш запрос в схему компоновки данных.
  2. Перейдем на вкладку Ресурсы.
  3. Для поля Сотрудник в колонке «Выражение» напишем функцию: СоединитьСтроки(Сотрудник, ", ").
  4. В настройках отчета добавим группировку по полям НачИнтервала и КонИнтервала.

Благодаря функции СоединитьСтроки(), платформа сама соберет всех сотрудников в одну ячейку, обеспечив наглядность отчета.

Альтернативный подход: Метод вех (счетчик)

Проанализируем еще один способ, который часто применяется в высоконагруженных системах планирования (WFM). Он называется «Метод вех» или метод накопительного итога. Выясним причину его популярности: он позволяет за один проход по данным определить не только пересечения, но и количество одновременно работающих людей (нагрузку).

Алгоритм метода:

  1. Для каждого начала смены создаем запись со значением +1.
  2. Для каждого окончания смены — запись со значением -1.
  3. Упорядочиваем все записи по времени.
  4. Вычисляем накопительный итог. В любой момент времени сумма покажет, сколько человек находится на смене.

Этот метод особенно полезен, если вам не нужно выводить фамилии, а требуется только построить график нагрузки на подразделение.

Работа с пустыми датами и исключениями

При реализации запроса в реальной конфигурации 1С (например, ЗУП или ERP) мы можем столкнуться с незаполненными датами окончания смены. Если в системе допустимо, что сотрудник заступил на смену, но еще не закончил ее, запрос может «потерять» такие интервалы. Выясним, как этого избежать.

Рекомендуется при помещении данных во временную таблицу использовать функцию ЕСТЬNULL или проверку на пустую дату. В случае пустой даты окончания, подставляйте максимально возможное значение в системе ДАТАВРЕМЯ(3999, 12, 31, 23, 59, 59). Это позволит алгоритму формирования интервалов корректно обработать «открытые» смены.

Рассмотренная методика формирования элементарных интервалов является универсальной и подходит для решения большинства задач, связанных с анализом пересекающихся периодов времени в 1С.

← На главную