При работе с виртуальными таблицами в языке запросов 1С (например, Хозрасчетный.Обороты) разработчики часто сталкиваются с необходимостью динамически вычислять границы периода. Попытка вставить условную конструкцию ВЫБОР КОГДА ... КОНЕЦ или функцию МАКСИМУМ непосредственно в параметры виртуальной таблицы НачалоПериода и КонецПериода приводит к ошибке синтаксиса.
Рассмотрим, почему возникают ограничения платформы и как правильно реализовать подобную логику в коде конфигурации.
Проанализируем механику работы виртуальных таблиц в платформе 1С. Параметры периода виртуальных таблиц служат для построения оптимизированных SQL-запросов к СУБД. В силу особенностей архитектуры платформа накладывает жесткие ограничения на выражения, допустимые в параметрах НачалоПериода и КонецПериода:
ВЫБОР, агрегатные функции (МАКСИМУМ, МИНИМУМ), подзапросы и соединения. Допускаются только простые параметры запроса, конкретные значения типа Дата, а также базовые функции НАЧАЛОПЕРИОДА, КОНЕЦПЕРИОДА и ДОБАВИТЬКДАТЕ.ОБЪЕДИНИТЬ ВСЕ.Наиболее эффективным и правильным подходом является вынос логики расчета границ периода из текста запроса в код 1С. Рассчитаем значения дат до передачи параметров в объект Запрос.
Разберем по шагам реализацию данного подхода:
&ДатаНачалаПериода и &ДатаОкончанияПериода.Посмотрим на пример кода:
// Расчет дат на стороне 1С
Если Месяц(УказаннаяДата) = 1 Тогда
ДатаНачала = НачалоГода(УказаннаяДата);
ДатаОкончания = КонецДня(НачалоГода(УказаннаяДата));
Иначе
ДатаНачала = НачалоГода(УказаннаяДата);
ДатаОкончания = КонецМесяца(ДобавитьМесяц(УказаннаяДата, -1));
КонецЕсли;
// Передача параметров в запрос
Запрос.УстановитьПараметр("ДатаНачалаПериода", ДатаНачала);
Запрос.УстановитьПараметр("ДатаОкончанияПериода", ДатаОкончания);
В самом тексте запроса параметр периода виртуальной таблицы указывается максимально просто:
ВЫБРАТЬ
РегистрОбороты.Счет КАК Счет,
РегистрОбороты.СуммаОборотДт КАК СуммаОборотДт
ИЗ
РегистрБухгалтерии.Хозрасчетный.Обороты(&ДатаНачалаПериода, &ДатаОкончанияПериода, , , , , , ) КАК РегистрОбороты
Если алгоритм выполняется в служебных модулях (например, при формировании проводок в процедурах вида ТекстОтраженияВРеглУчете() в 1С:ERP), текст запроса формируется программно. В этом случае условный оператор Если ... Тогда проверяется в коде модуля, а в сам текст запроса подставляется нужный фрагмент.
Рассмотрим пример генерации текста:
Если Месяц(ПараметрыОтражения.Дата) = 1 Тогда
ТекстВыраженияПериода = "НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ)";
Иначе
ТекстВыраженияПериода = "КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1), МЕСЯЦ)";
КонецЕсли;
ТекстЗапроса = "
|ВЫБРАТЬ
| ХозрасчетныйОбороты.Счет,
| ХозрасчетныйОбороты.СуммаОборот
|ИЗ
| РегистрБухгалтерии.Хозрасчетный.Обороты(НАЧАЛОПЕРИОДА(&Дата, ГОД), " + ТекстВыраженияПериода + ", , , , , , ) КАК ХозрасчетныйОбороты";
Если условие обязательно должно вычисляться полностью внутри запроса без предварительной установки параметров из кода, можно отказаться от применения виртуальной таблицы и обратиться напрямую к реальной (физической) таблице движений.
В секции ГДЕ реальной таблицы платформой разрешено использовать конструкции ВЫБОР КОГДА и сложные функции работы с датами. При этом необходимо явно прописать группировку и суммирование ресурсов.
Проанализируем пример такого запроса:
ВЫБРАТЬ
Движения.СчетДт КАК Счет,
СУММА(Движения.Сумма) КАК СуммаОборотДт
ИЗ
РегистрБухгалтерии.Хозрасчетный КАК Движения
ГДЕ
Движения.Период МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, ГОД) И
ВЫБОР
КОГДА МЕСЯЦ(&Дата) = 1
ТОГДА КОНЕЦПЕРИОДА(НАЧАЛОПЕРИОДА(&Дата, ГОД), ДЕНЬ)
ИНАЧЕ КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, -1), МЕСЯЦ)
КОНЕЦ
СГРУППИРОВАТЬ ПО
Движения.СчетДт
Важно: Обращение к физической таблице может уступать по производительности виртуальным таблицам на больших объемах данных, поэтому данный метод стоит использовать только при отсутствии возможности рассчитать параметры в коде 1С.