Как преобразовать и заполнить интервалы дат в запросе 1С

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

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

Анализ исходных данных и правил преобразования

Проанализируем ситуацию на примере исходной таблицы, в которой содержатся даты начала, даты завершения и булево состояние (ИСТИНА / ЛОЖЬ, или «Да» / «Нет»):

  1. Пересечение периодов: Если новый интервал начинаются внутри уже существующего периода с аналогичным состоянием (например, интервал с 13.01.2017 попадает в отрезок 11.01.2017–20.01.2017 со статусом ИСТИНА), он поглощается более широким интервалом.
  2. Заполнение пропусков (гапов): Если между периодами есть временной разрыв (например, между 20.01.2017 и 02.02.2017), в результирующую таблицу добавляется новый интервал (21.01.2017–01.02.2017) со статусом по умолчанию ЛОЖЬ («Нет»).
  3. Обработка незавершенных дат: Пустая дата окончания (01.01.0001) означает, что состояние действует до момента следующего изменения статуса.

Подготовка тестовой таблицы в запросе

Для отладки алгоритмов создадим временную таблицу ВТ прямо в консоли запросов 1С с помощью конструкции ОБЪЕДИНИТЬ ВСЕ:


ВЫБРАТЬ
	ДАТАВРЕМЯ(2017, 1, 5, 0, 0, 0) КАК Начало,
	ДАТАВРЕМЯ(2017, 1, 10, 0, 0, 0) КАК Конец,
	ЛОЖЬ КАК Статус
ПОМЕСТИТЬ ВТ

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	ДАТАВРЕМЯ(2017, 1, 11, 0, 0, 0),
	ДАТАВРЕМЯ(2017, 1, 20, 0, 0, 0),
	ИСТИНА

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	ДАТАВРЕМЯ(2017, 1, 13, 0, 0, 0),
	ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0),
	ИСТИНА

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	ДАТАВРЕМЯ(2017, 2, 2, 0, 0, 0),
	ДАТАВРЕМЯ(2017, 2, 10, 0, 0, 0),
	ИСТИНА

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	ДАТАВРЕМЯ(2017, 2, 12, 0, 0, 0),
	ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0),
	ИСТИНА

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
	ДАТАВРЕМЯ(2017, 2, 18, 0, 0, 0),
	ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0),
	ЛОЖЬ;

Способ 1. Изменение архитектуры на регистр сведений

Наиболее эффективный способ избежать сложных вычислительных запросов — правильно спроектировать хранение данных. В платформе 1С для работы с состояниями во времени предназначен периодический регистр сведений.

Если хранить в регистре сведений только момент изменения состояния (реквизит Период) и само значение Состояние, то реквизит «ДатаЗавершения» становится не нужен. Дата завершения текущей записи автоматически считается датой начала следующей записи минус один день.

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

Способ 2. Построение элементарных интервалов в запросе

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

  1. Извлечение контрольных точек: Выбираем все уникальные даты начала и даты окончания. Пустые даты завершения заменяем заведомо максимальной датой с помощью ВЫБОР КОГДА. Для дат окончания рассчитываем дату следующего дня через функцию ДОБАВИТЬКДАТЕ(Дата, ДЕНЬ, 1).
  2. Формирование базовых отрезков: Соединением контрольных дат «само на себя» формируем набор элементарных непересекающихся интервалов.
  3. Определение статуса: Каждому элементарному отрезку левым соединением сопоставляем исходные данные. Пропущенным периодам присваиваем статус ЛОЖЬ с помощью функции ЕСТЬNULL.
  4. Сворачивание смежных интервалов: Группируем последовательные элементарные интервалы с одинаковым статусом, вычисляя минимальную дату начала и максимальную дату окончания.

Способ 3. Постобработка выборки в коде 1С

Поскольку алгоритмы слияния интервалов в языке запросов 1С требуют соединений таблиц по условиям неравенства (что создает высокую нагрузку на СУБД при больших объемах данных), на практике часто применяют программную обработку:

Выгружаем результат первичного запроса в объект ТаблицаЗначений, сортируем по дате начала и обходим массив записей в цикле. Такой подход позволяет за один проход объединить накладывающиеся отрезки, вставить недостающие периоды «Нет» и сформировать итоговую таблицу без нагрузки на базу данных.

← На главную