Как получить список дат с интервалом в две недели в запросе 1С?

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

При разработке отчетов и механизмов расчета периодически возникает задача получить последовательность дат с заданным шагом (например, смещение на две недели назад от текущей даты до начала года). Так как язык запросов 1С не поддерживает циклы и рекурсивные выражения (Common Table Expressions / CTE), прямое циклическое вычисление внутри одного запроса невозможно.

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

Способ 1. Генерация последовательности чисел в запросе

Проанализируем подход, при котором динамическая последовательность шагов формируется прямо в запросе. Для этого создается временная таблица с цифрами от 0 до 9, после чего выполняется её декартово произведение (внутреннее соединение по условию ПО ИСТИНА). Это позволяет сгенерировать ряды чисел (0, 1, 2, ..., N), которые затем умножаются на нужный интервал в днях (14 дней = 2 недели) и вычитаются из начальной даты с помощью функции ДОБАВИТЬКДАТЕ.

Рассмотрим пример запроса:


ВЫБРАТЬ
	0 КАК Цифры
ПОМЕСТИТЬ ВТ_Цифры

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

ВЫБРАТЬ 1
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 2
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 3
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 4
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 5
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 6
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 7
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 8
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ 9
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
	ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -(ВТ_Цифры.Цифры + ВТ_Цифры1.Цифры * 10 + ВТ_Цифры2.Цифры * 100) * 14) КАК ДатаСИнтервалом2Недели
ИЗ
	ВТ_Цифры КАК ВТ_Цифры
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Цифры КАК ВТ_Цифры1
		ПО (ИСТИНА)
		ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Цифры КАК ВТ_Цифры2
		ПО (ИСТИНА)
ГДЕ
	ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -(ВТ_Цифры.Цифры + ВТ_Цифры1.Цифры * 10 + ВТ_Цифры2.Цифры * 100) * 14) >= &ДатаНачала
УПОРЯДОЧИТЬ ПО
	ДатаСИнтервалом2Недели УБЫВ

Разберем детально, как работает этот код:

  1. Во временной таблице ВТ_Цифры создаются 10 строк с числами от 0 до 9.
  2. Тройное декартово соединение таблицы ВТ_Цифры само с собой позволяет сформировать диапазон значений от 0 до 999.
  3. Формула -(ВТ_Цифры.Цифры + ВТ_Цифры1.Цифры * 10 + ВТ_Цифры2.Цифры * 100) * 14 переводит индекс строки в смещение на нужную величину в днях.
  4. Функция ДОБАВИТЬКДАТЕ вычитает полученное количество дней из параметра &ТекущаяДата.
  5. Условие в секции ГДЕ ограничивает выборку требуемым периодом (например, параметром &ДатаНачала).

Способ 2. Подготовка таблицы значений в встроенном языке 1С

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

Посмотрим на пример реализации в коде:


КоличествоСекундВСутках = 86400;
ИнтервалДвеНедели = 14 * КоличествоСекундВСутках;

ТекДата = ТекущаяДатаСеанса();
НачалоПериода = НачалоГода(ТекДата);

ТаблицаДат = Новый ТаблицаЗначений;
ТаблицаДат.Колонки.Добавить("Период", Новый ОписаниеТипов("Дата"));

Пока ТекДата >= НачалоПериода Цикл
	НоваяСтрока = ТаблицаДат.Добавить();
	НоваяСтрока.Период = ТекДата;
	ТекДата = ТекДата - ИнтервалДвеНедели;
КонецЦикла;

Запрос = Новый Запрос;
Запрос.Текст = 
	"ВЫБРАТЬ
	|	ТЗ.Период КАК ДатаИнтервала
	|ПОМЕСТИТЬ ВТ_Даты
	|ИЗ
	|	&МассивДат КАК ТЗ";

Запрос.УстановитьПараметр("МассивДат", ТаблицаДат);

Этот подход гарантирует высокую скорость работы и наглядность алгоритма, так как подготовка данных происходит в оперативной памяти до передачи в СУБД.

Способ 3. Выборка из таблицы производственного календаря

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

Рассмотрим пример запроса по существующему календарю:


ВЫБРАТЬ
	Календарь.Дата КАК ДатаСИнтервалом
ИЗ
	РегистрСведений.ПроизводственныйКалендарь КАК Календарь
ГДЕ
	Календарь.Дата <= &ТекущаяДата
	И Календарь.Дата >= &ДатаНачала
	И РАЗНОСТЬДАТ(Календарь.Дата, &ТекущаяДата, ДЕНЬ) - ВЫРАЗИТЬ(РАЗНОСТЬДАТ(Календарь.Дата, &ТекущаяДата, ДЕНЬ) / 14 - 0.5 КАК ЧИСЛО(10, 0)) * 14 = 0
УПОРЯДОЧИТЬ ПО
	ДатаСИнтервалом УБЫВ

Важный момент: при использовании вычисляемых функций (таких как РАЗНОСТЬДАТ) в условиях фильтрации ГДЕ, СУБД не может применить индексы по полю даты, что может снизить производительность при выборке из больших таблиц. Поэтому для частых и критичных к скорости вычислений рекомендуется применять Способ 2 или механизмы схемы компоновки данных (СКД) с настройкой Дополнения периодов.

← На главную