При разработке отчетов на платформе 1С:Предприятие 8 часто возникают ситуации, когда стандартного конструктора запросов в Системе компоновки данных (СКД) недостаточно — для таких задач пригодится инструментарий разработчика с консолью СКД и запросов. Бывает необходимо сформировать текст запроса динамически, в зависимости от условий, выбранных пользователем, или передать в отчет данные, полученные сложным путем в программном коде. В этой статье мы подробно разберем, как правильно реализовать программную передачу запроса в СКД, сохранив при этом все преимущества системы: отборы, группировки и оформление.
Этот метод считается "классическим" и часто встречается в типовых конфигурациях (например, в 1С:Управление торговлей 11 или 1С:Зарплата и управление персоналом 3). Основная идея заключается в том, чтобы подготовить в схеме компоновки "скелет" запроса, а затем программно заменить его на нужный нам текст.
Шаг 1: Подготовка схемы в конфигураторе
В конструкторе СКД создадим набор данных - запрос — для этого есть редактор запросов СКД в пользовательском режиме. Чтобы компоновщик настроек "видел" доступные поля для отборов и группировок, нам нужно описать их. Рассмотрим пример, где мы выбираем пустые значения нужных типов:
ВЫБРАТЬ
ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка) КАК Организация,
ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) КАК Контрагент,
0 КАК СуммаОстаток
Шаг 2: Программная обработка в модуле отчета
Перейдем в модуль отчета и воспользуемся обработчиком события ПриКомпоновкеДанных. Нам необходимо установить СтандартнаяОбработка = Ложь, чтобы самостоятельно управлять процессом формирования отчета.
Проанализируем следующий пример кода:
Процедура ПриКомпоновкеДанных(ПараметрыВывода, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// 1. Получаем настройки пользователя
НастройкиОтчета = КомпоновщикНастроек.ПолучитьНастройки();
// 2. Формируем новый текст запроса
НовыйТекстЗапроса =
"ВЫБРАТЬ
| Продажи.Организация КАК Организация,
| Продажи.Контрагент КАК Контрагент,
| Продажи.СуммаОборорт КАК СуммаОстаток
|ИЗ
| РегистрНакопления.Продажи КАК Продажи";
// 3. Подменяем текст запроса в схеме
СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Запрос = НовыйТекстЗапроса;
// 4. Инициализируем макет компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки);
// 5. Процессор компоновки и вывода
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
При прямом изменении СхемаКомпоновкиДанных в сеансе пользователя настройки могут закэшироваться, что приведет к непредсказуемому поведению при повторном открытии отчета. Проанализируем более безопасный подход — использование копии схемы.
Для создания независимой копии объекта схемы используем СериализаторXDTO. Это гарантирует, что наши изменения не затронут основную схему отчета:
КопияСхемы = СериализаторXDTO.Копировать(СхемаКомпоновкиДанных);
НаборДанных = КопияСхемы.НаборыДанных.Найти("НаборДанных1");
Если НаборДанных <> Неопределено Тогда
НаборДанных.Запрос = "ВЫБРАТЬ ..."; // Ваш динамический запрос
КонецЕсли;
После этого в методе КомпоновщикМакета.Выполнить() нужно использовать именно КопияСхемы.
Когда мы программно передаем текст запроса, важно помнить, что СКД должна уметь накладывать пользовательские фильтры. Чтобы это работало корректно, в тексте запроса следует использовать фигурные скобки {}. Это так называемое расширение языка запросов СКД.
Рассмотрим пример правильного оформления запроса для подмены:
ТекстЗапроса =
"ВЫБРАТЬ
| Реализация.Ссылка КАК Ссылка,
| Реализация.Дата КАК Дата,
| Реализация.СуммаДокумента КАК Сумма
|{ВЫБРАТЬ Ссылка.*, Дата, Сумма}
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Проведен = ИСТИНА
|{ГДЕ Реализация.Организация.* КАК Организация}";
Использование {ВЫБРАТЬ ...} и {ГДЕ ...} позволяет СКД динамически добавлять поля в выборку и условия в секцию ГДЕ, основываясь на том, что пользователь указал в настройках отчета.
Выясним причину, по которой иногда метод "пустых полей" не подходит. Если структура запроса заранее неизвестна (например, количество колонок зависит от данных в базе), нам придется программно создавать поля набора данных.
Для этого мы обращаемся к коллекции Поля нашего набора данных. Разберем шаги:
НаборДанныхЗапросСхемыКомпоновкиДанных.
НовоеПоле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
НовоеПоле.ПутьКДанным = "Контрагент";
НовоеПоле.Поле = "Контрагент";
НовоеПоле.Заголовок = "Клиент";
НовоеПоле.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.Контрагенты");
Этот способ более трудоемкий, но он позволяет строить отчеты на базе абсолютно произвольных структур данных. Для упрощения подобной разработки можно использовать модуль-обёртку над объектной моделью СКД.
Иногда запрос проще выполнить отдельно через объект Запрос, получить ТаблицаЗначений, а уже её передать в СКД. Рассмотрим, как это сделать правильно.
В схеме СКД создаем Набор данных - объект и указываем имя внешнего набора данных (например, "ВнешняяТаблицаПродаж"). Программный код передачи данных будет выглядеть так:
// Предположим, ТЗ_Данные - это сформированная Таблица Значений
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ВнешняяТаблицаПродаж", ТЗ_Данные);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Передаем структуру внешних наборов во втором параметре метода Инициализировать
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);
Важный нюанс: Ключ в структуре ВнешниеНаборыДанных должен символ в символ совпадать с именем объекта, указанным в схеме СКД.
Проанализируем влияние программной подмены на скорость работы. СКД славится тем, что оптимизирует запросы: выбрасывает неиспользуемые соединения и поля. Если вы передаете в НаборДанных.Запрос жестко заданный сложный текст без расширений {}, вы лишаете систему возможности оптимизации.
Рекомендации:
ПриКомпоновкеДанных всегда проверяйте наличие необходимых параметров в КомпоновщикНастроек.Настройки.ПараметрыДанных.Таким образом, мы рассмотрели основные способы программного управления запросами в СКД. Выбор конкретного метода зависит от ваших задач: для типовых отчетов лучше подходит подмена текста в ПриКомпоновкеДанных, а для сложных интеграций или динамических структур — использование внешних наборов данных или программное формирование полей схемы.