При разработке отчетов на базе системы компоновки данных (СКД) разработчики нередко сталкиваются с ситуацией, когда запрос, идеально работающий в консоли запросов, при переносе в СКД начинает выдавать неверные данные либо вовсе завершается ошибкой. Чаще всего это происходит при попытке динамически рассчитать границы периода (например, начало текущего месяца) прямо внутри вызова виртуальной таблицы регистра накопления.
Разберем детально, почему возникает эта проблема и как правильно настроить параметры и текст запроса в схеме компоновки данных.
Рассмотрим типовой ошибочный запрос, в котором выполняется попытка получить обороты за два разных временных среза:
ВЫБРАТЬ
АС_УчетГСМОбороты.Номенклатура КАК Карта,
NULL КАК СНачалаПериода,
АС_УчетГСМОбороты.КоличествоПриход КАК Расход
ПОМЕСТИТЬ ВТ
ИЗ
РегистрНакопления.АС_УчетГСМ.Обороты(&НачалоПериода, &КонецПериода, , ) КАК АС_УчетГСМОбороты
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
АС_УчетГСМОбороты.Номенклатура,
АС_УчетГСМОбороты.КоличествоПриход,
NULL
ИЗ
РегистрНакопления.АС_УчетГСМ.Обороты(НАЧАЛОПЕРИОДА(&НачалоПериода, МЕСЯЦ), &НачалоПериода, Период, ) КАК АС_УчетГСМОбороты
Проанализируем причины некорректной работы такого запроса в СКД:
Обороты или ОстаткиИОбороты) нельзя использовать функции языка запросов вроде НАЧАЛОПЕРИОДА(...). Виртуальные таблицы принимают исключительно имена параметров (через &) или литералы.&НачалоПериода и &КонецПериода. В результате вторая таблица объединения получает те же самые границы, что и первая, перетирая логику разработчика.Чтобы СКД корректно рассчитала начало месяца и передала его в параметры нужной виртуальной таблицы, выполним следующую последовательность действий.
Перейдем на вкладку «Параметры» схемы компоновки данных и добавим новый параметр с именем НачалоМесяца (тип — Дата).
В колонке «Выражение» для параметра НачалоМесяца пропишем формулу на языке выражений СКД:
НАЧАЛОПЕРИОДА(&НачалоПериода, "МЕСЯЦ")
Обратите внимание: в языке выражений СКД название периодичности ("МЕСЯЦ", "ДЕНЬ", "ГОД") обязательно указывается в двойных кавычках как строковый литерал.
Установим для параметра НачалоМесяца флажок «Ограничение доступности». Это гарантирует, что пользователь отчета не увидит технический параметр в настройках, а значение будет рассчитываться автоматически на основании выбранного пользователем параметра &НачалоПериода.
Чтобы механизм автозаполнения СКД не переопределял границы периода, параметры виртуальной таблицы необходимо заключить в фигурные скобки {}. Приведем исправленный фрагмент запроса:
ВЫБРАТЬ
АС_УчетГСМОбороты.Номенклатура КАК Карта,
0 КАК СНачалаПериода,
АС_УчетГСМОбороты.КоличествоПриход КАК Расход
ПОМЕСТИТЬ ВТ
ИЗ
РегистрНакопления.АС_УчетГСМ.Обороты({&НачалоПериода}, {&КонецПериода}, , ) КАК АС_УчетГСМОбороты
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
АС_УчетГСМОбороты.Номенклатура,
АС_УчетГСМОбороты.КоличествоПриход,
0
ИЗ
РегистрНакопления.АС_УчетГСМ.Обороты({&НачалоМесяца}, {&НачалоПериода}, Период, ) КАК АС_УчетГСМОбороты
Важное замечание по значениям NULL: В операциях ОБЪЕДИНИТЬ ВСЕ для числовых полей, которые в дальнейшем будут агрегироваться функцией СУММА(), рекомендуется заменять литерал NULL на 0. Это предотвращает потенциальные ошибки при арифметических вычислениях в итоговых запросах.
Рассмотрим еще один важный нюанс: при передаче граничных дат в таблицы оборотов условие включения записей работает как Период >= НачалоПериода И Период <= КонецПериода. Если конец первого интервала точно совпадает с началом второго (например, обе границы приходятся на &НачалоПериода 00:00:00), движения, зарегистрированные ровно на эту секунду, попадут в обе выборки.
Чтобы избежать двойного учета на стыке интервалов, для верхнего предела вычисляемого интервала можно создать дополнительный параметр со смещением:
ДобавитьКДате(&НачалоПериода, "Секунда", -1)
Либо, если отчет формируется за дни, приводить пользовательский конец периода к концу дня через выражение КонецПериода(&КонецПериода, "День").
В зависимости от структуры данных и требований к отчету можно применить и другие архитектурные решения в СКД:
ОстаткиИОбороты за весь период и рассчитывать показатели с начала месяца средствами языка выражений СКД в ресурсах или вычисляемых полях.
Сумма(Выбор Когда Период < &НачалоПериода Тогда КоличествоПриход Иначе 0 Конец)