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