При разработке сложных отчетов на системе компоновки данных (СКД) часто возникает задача: предоставить пользователю выбор между принципиально разными алгоритмами получения данных в рамках одного отчета. Например, в одном режиме нужно вывести всю номенклатуру из базы, а в другом — только ту, по которой были продажи за период. Разберем подробно, как реализовать такую логику, какие ошибки совершают новички при программной подмене схемы и как оптимизировать запросы для работы с объемными данными, такими как справочники системы Меркурий (ВетИС).
Рассмотрим типичную ситуацию, с которой столкнулся автор темы. При попытке программно переключить схему в процедуре ПриКомпоновкеРезультата возникает ошибка: "Не задано значение параметра Номенклатура". Выясним причину. Даже если в настройках СКД параметр помечен как необязательный, платформа будет требовать его заполнения, если в тексте запроса он прописан в жестком условии ГДЕ.
Проанализируем классический синтаксис условия:
ГДЕ РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&Номенклатура)
В таком виде параметр &Номенклатура обязан иметь значение. Чтобы сделать его по-настоящему необязательным, необходимо использовать расширение языка запросов СКД — фигурные скобки. Пропишем условие следующим образом:
{ГДЕ (РеализацияТоваровУслугТовары.Номенклатура В ИЕРАРХИИ (&Номенклатура))}
Теперь, если пользователь не заполнит номенклатуру на форме, СКД просто проигнорирует это условие при генерации итогового запроса к СУБД.
Вместо того чтобы плодить разные макеты СКД, рассмотрим более элегантный способ — объединение запросов в одном наборе данных. Мы добавим фиктивный параметр &ВидПоиска, который будет определять, какая часть запроса вернет данные.
Разберем структуру такого запроса:
// Часть 1: Вся номенклатура
ВЫБРАТЬ
Номенклатура.Ссылка КАК Номенклатура,
1 КАК ВидПоиска
ИЗ
Справочник.Номенклатура КАК Номенклатура
ГДЕ
&ВидПоиска = 1
ОБЪЕДИНИТЬ ВСЕ
// Часть 2: Только проданная номенклатура
ВЫБРАТЬ РАЗЛИЧНЫЕ
РеализацияТовары.Номенклатура,
2 КАК ВидПоиска
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
ГДЕ
&ВидПоиска = 2
И РеализацияТовары.Ссылка.Дата МЕЖДУ &ДатаНачало И &ДатаОкончание
Важный нюанс оптимизации: Чтобы СКД не выполняла обе части запроса одновременно (что крайне медленно), необходимо использовать конструкцию {ГДЕ 1 = &ВидПоиска} внутри подзапросов. Это позволит оптимизатору 1С отсечь ненужную ветку еще на этапе подготовки данных.
Если структуры отчетов (колонки, группировки) сильно различаются, можно использовать подход с несколькими макетами СКД. Рассмотрим, как правильно переключить схему программно, не потеряв пользовательские настройки.
Проанализируем шаги в модуле отчета:
СхемаКомпоновкиДанных объекта отчета.Посмотрим на пример кода:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отключаем стандартный вывод
// 1. Выбираем макет
Если ВидПоиска = 1 Тогда
ТекущаяСхема = ЭтотОбъект.ПолучитьМакет("ВсяНоменклатура");
Иначе
ТекущаяСхема = ЭтотОбъект.ПолучитьМакет("ПроданнаяНоменклатура");
КонецЕсли;
// 2. Инициализируем компоновщик с новой схемой
ИсточникНастроек = Новый ИсточникДоступныхНастроекКомпоновкиДанных(ТекущаяСхема);
ЭтотОбъект.КомпоновщикНастроек.Инициализировать(ИсточникНастроек);
// 3. Загружаем настройки (например, настройки по умолчанию из макета)
ЭтотОбъект.КомпоновщикНастроек.ЗагрузитьНастройки(ТекущаяСхема.НастройкиПоУмолчанию);
// 4. Устанавливаем параметры программно
Параметры = ЭтотОбъект.КомпоновщикНастроек.Настройки.ПараметрыДанных;
Параметры.УстановитьЗначениеПараметра("ДатаНачало", НачалоПериода);
Параметры.УстановитьЗначениеПараметра("ДатаОкончание", КонецПериода);
// 5. Выполняем компоновку
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(ТекущаяСхема, ЭтотОбъект.КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
В современных конфигурациях на управляемых формах (УТ 11, ERP 2.5) рекомендуется не писать сложный код переключения схем, а использовать Варианты отчета. Для каждого режима (Вся номенклатура / Продажи) создается свой вариант в одной и той же СКД (или в разных).
Пользователь выбирает вариант в стандартном меню "Все действия — Выбрать вариант", и система автоматически подтягивает нужные настройки, отборы и даже визуальное оформление. Это избавляет программиста от поддержки процедур обработки параметров вручную.
В запросе автора используются тяжелые соединения со справочниками Vetis_НаименованияПродукции и регистрами соответствия. Такие запросы могут выполняться минутами на больших базах. Проанализируем, как ускорить отчет.
Использование временных таблиц: Вместо огромного внутреннего соединения справочников с табличной частью документа, сначала выберем проданную номенклатуру во временную таблицу.
Рассмотрим шаги оптимизации:
ВТ_ПроданныеТовары, куда выбираем только ССЫЛКУ на номенклатуру из реализаций за указанный период.Номенклатура.ВТ_ПроданныеТовары с данными ВетИС.Это позволит SQL-серверу сначала сократить выборку до нескольких сотен позиций и только потом "подтягивать" тяжелые данные по ГУИДам и производителям. Помните, что СКД плохо работает с ЛЕВЫМИ СОЕДИНЕНИЯМИ к виртуальным таблицам и сложным справочникам, если они стоят в начале запроса.
Дополнительный совет: Если данные ВетИС хранятся во внешних источниках или очень специфичны, попробуйте передать их в СКД через Внешний набор данных (Объект). Сначала получите таблицу значений программно с помощью простого запроса, а затем передайте её в процессор компоновки. Это даст вам 100% контроль над скоростью получения данных.