Как реализовать отчет с двумя схемами СКД или разными режимами выборки данных?

Программист 1С v8.3 (Обычные формы) Управленческий учет Торговля и дистрибуция
← На главную

При разработке сложных отчетов на системе компоновки данных (СКД) часто возникает задача: предоставить пользователю выбор между принципиально разными алгоритмами получения данных в рамках одного отчета. Например, в одном режиме нужно вывести всю номенклатуру из базы, а в другом — только ту, по которой были продажи за период. Разберем подробно, как реализовать такую логику, какие ошибки совершают новички при программной подмене схемы и как оптимизировать запросы для работы с объемными данными, такими как справочники системы Меркурий (ВетИС).

Причина проблемы: обязательные параметры и синтаксис запроса

Рассмотрим типичную ситуацию, с которой столкнулся автор темы. При попытке программно переключить схему в процедуре ПриКомпоновкеРезультата возникает ошибка: "Не задано значение параметра Номенклатура". Выясним причину. Даже если в настройках СКД параметр помечен как необязательный, платформа будет требовать его заполнения, если в тексте запроса он прописан в жестком условии ГДЕ.

Проанализируем классический синтаксис условия:

ГДЕ РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&Номенклатура)

В таком виде параметр &Номенклатура обязан иметь значение. Чтобы сделать его по-настоящему необязательным, необходимо использовать расширение языка запросов СКД — фигурные скобки. Пропишем условие следующим образом:

{ГДЕ (РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&Номенклатура))}

Теперь, если пользователь не заполнит номенклатуру на форме, СКД просто проигнорирует это условие при генерации итогового запроса к СУБД.

Решение 1: Использование одного набора данных и объединения (UNION)

Вместо того чтобы плодить разные макеты СКД, рассмотрим более элегантный способ — объединение запросов в одном наборе данных. Мы добавим фиктивный параметр &ВидПоиска, который будет определять, какая часть запроса вернет данные.

Разберем структуру такого запроса:


// Часть 1: Вся номенклатура
ВЫБРАТЬ
    Номенклатура.Ссылка КАК Номенклатура,
    1 КАК ВидПоиска
ИЗ
    Справочник.Номенклатура КАК Номенклатура
ГДЕ
    &ВидПоиска = 1

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

// Часть 2: Только проданная номенклатура
ВЫБРАТЬ РАЗЛИЧНЫЕ
    РеализацияТовары.Номенклатура,
    2 КАК ВидПоиска
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
ГДЕ
    &ВидПоиска = 2
    И РеализацияТовары.Ссылка.Дата МЕЖДУ &ДатаНачало И &ДатаОкончание

Важный нюанс оптимизации: Чтобы СКД не выполняла обе части запроса одновременно (что крайне медленно), необходимо использовать конструкцию {ГДЕ 1 = &ВидПоиска} внутри подзапросов. Это позволит оптимизатору 1С отсечь ненужную ветку еще на этапе подготовки данных.

Решение 2: Программная подмена схемы в ПриКомпоновкеРезультата

Если структуры отчетов (колонки, группировки) сильно различаются, можно использовать подход с несколькими макетами СКД. Рассмотрим, как правильно переключить схему программно, не потеряв пользовательские настройки.

Проанализируем шаги в модуле отчета:

  1. Определяем, какой макет нужен на основе выбора пользователя.
  2. Подменяем свойство СхемаКомпоновкиДанных объекта отчета.
  3. Критически важный момент: заново инициализируем компоновщик настроек, так как старый привязан к предыдущей схеме.
  4. Переносим значения параметров (даты, контрагентов) из реквизитов формы в новые настройки.

Посмотрим на пример кода:


Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Отключаем стандартный вывод
    
    // 1. Выбираем макет
    Если ВидПоиска = 1 Тогда
        ТекущаяСхема = ЭтотОбъект.ПолучитьМакет("ВсяНоменклатура");
    Иначе
        ТекущаяСхема = ЭтотОбъект.ПолучитьМакет("ПроданнаяНоменклатура");
    КонецЕсли;
    
    // 2. Инициализируем компоновщик с новой схемой
    ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(ТекущаяСхема);
    ЭтотОбъект.КомпоновщикНастроек.Инициализировать(ИсточникНастроек);
    
    // 3. Загружаем настройки (например, настройки по умолчанию из макета)
    ЭтотОбъект.КомпоновщикНастроек.ЗагрузитьНастройки(ТекущаяСхема.НастройкиПоУмолчанию);
    
    // 4. Устанавливаем параметры программно
    Параметры = ЭтотОбъект.КомпоновщикНастроек.Настройки.ПараметрыДанных;
    Параметры.УстановитьЗначениеПараметра("ДатаНачало", НачалоПериода);
    Параметры.УстановитьЗначениеПараметра("ДатаОкончание", КонецПериода);
    
    // 5. Выполняем компоновку
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(ТекущаяСхема, ЭтотОбъект.КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Решение 3: Варианты отчета (Самый современный способ)

В современных конфигурациях на управляемых формах (УТ 11, ERP 2.5) рекомендуется не писать сложный код переключения схем, а использовать Варианты отчета. Для каждого режима (Вся номенклатура / Продажи) создается свой вариант в одной и той же СКД (или в разных).

Пользователь выбирает вариант в стандартном меню "Все действия — Выбрать вариант", и система автоматически подтягивает нужные настройки, отборы и даже визуальное оформление. Это избавляет программиста от поддержки процедур обработки параметров вручную.

Оптимизация работы с таблицами ВетИС (Меркурий)

В запросе автора используются тяжелые соединения со справочниками Vetis_НаименованияПродукции и регистрами соответствия. Такие запросы могут выполняться минутами на больших базах. Проанализируем, как ускорить отчет.

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

Рассмотрим шаги оптимизации:

  1. Создаем временную таблицу ВТ_ПроданныеТовары, куда выбираем только ССЫЛКУ на номенклатуру из реализаций за указанный период.
  2. Обязательно индексируем временную таблицу по полю Номенклатура.
  3. Во втором запросе соединяем нашу ВТ_ПроданныеТовары с данными ВетИС.

Это позволит SQL-серверу сначала сократить выборку до нескольких сотен позиций и только потом "подтягивать" тяжелые данные по ГУИДам и производителям. Помните, что СКД плохо работает с ЛЕВЫМИ СОЕДИНЕНИЯМИ к виртуальным таблицам и сложным справочникам, если они стоят в начале запроса.

Дополнительный совет: Если данные ВетИС хранятся во внешних источниках или очень специфичны, попробуйте передать их в СКД через Внешний набор данных (Объект). Сначала получите таблицу значений программно с помощью простого запроса, а затем передайте её в процессор компоновки. Это даст вам 100% контроль над скоростью получения данных.

← На главную