Как программно передать или изменить запрос в СКД

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке отчетов на платформе 1С:Предприятие 8 часто возникают ситуации, когда стандартного конструктора запросов в Системе компоновки данных (СКД) недостаточно — для таких задач пригодится инструментарий разработчика с консолью СКД и запросов. Бывает необходимо сформировать текст запроса динамически, в зависимости от условий, выбранных пользователем, или передать в отчет данные, полученные сложным путем в программном коде. В этой статье мы подробно разберем, как правильно реализовать программную передачу запроса в СКД, сохранив при этом все преимущества системы: отборы, группировки и оформление.

Метод 1: Подмена текста запроса в существующей схеме

Этот метод считается "классическим" и часто встречается в типовых конфигурациях (например, в 1С:Управление торговлей 11 или 1С:Зарплата и управление персоналом 3). Основная идея заключается в том, чтобы подготовить в схеме компоновки "скелет" запроса, а затем программно заменить его на нужный нам текст.

Шаг 1: Подготовка схемы в конфигураторе

В конструкторе СКД создадим набор данных - запрос — для этого есть редактор запросов СКД в пользовательском режиме. Чтобы компоновщик настроек "видел" доступные поля для отборов и группировок, нам нужно описать их. Рассмотрим пример, где мы выбираем пустые значения нужных типов:


ВЫБРАТЬ
    ЗНАЧЕНИЕ(Справочник.Организации.ПустаяСсылка) КАК Организация,
    ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка) КАК Контрагент,
    0 КАК СуммаОстаток

Шаг 2: Программная обработка в модуле отчета

Перейдем в модуль отчета и воспользуемся обработчиком события ПриКомпоновкеДанных. Нам необходимо установить СтандартнаяОбработка = Ложь, чтобы самостоятельно управлять процессом формирования отчета.

Проанализируем следующий пример кода:


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

Метод 2: Работа с копией схемы через XDTO

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

Для создания независимой копии объекта схемы используем СериализаторXDTO. Это гарантирует, что наши изменения не затронут основную схему отчета:


КопияСхемы = СериализаторXDTO.Копировать(СхемаКомпоновкиДанных);
НаборДанных = КопияСхемы.НаборыДанных.Найти("НаборДанных1");
Если НаборДанных <> Неопределено Тогда
    НаборДанных.Запрос = "ВЫБРАТЬ ..."; // Ваш динамический запрос
КонецЕсли;

После этого в методе КомпоновщикМакета.Выполнить() нужно использовать именно КопияСхемы.

Важность расширения языка запросов СКД

Когда мы программно передаем текст запроса, важно помнить, что СКД должна уметь накладывать пользовательские фильтры. Чтобы это работало корректно, в тексте запроса следует использовать фигурные скобки {}. Это так называемое расширение языка запросов СКД.

Рассмотрим пример правильного оформления запроса для подмены:


ТекстЗапроса = 
"ВЫБРАТЬ
|   Реализация.Ссылка КАК Ссылка,
|   Реализация.Дата КАК Дата,
|   Реализация.СуммаДокумента КАК Сумма
|{ВЫБРАТЬ Ссылка.*, Дата, Сумма}
|ИЗ
|   Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
|   Реализация.Проведен = ИСТИНА
|{ГДЕ Реализация.Организация.* КАК Организация}";

Использование {ВЫБРАТЬ ...} и {ГДЕ ...} позволяет СКД динамически добавлять поля в выборку и условия в секцию ГДЕ, основываясь на том, что пользователь указал в настройках отчета.

Метод 3: Полностью динамическое создание полей

Выясним причину, по которой иногда метод "пустых полей" не подходит. Если структура запроса заранее неизвестна (например, количество колонок зависит от данных в базе), нам придется программно создавать поля набора данных.

Для этого мы обращаемся к коллекции Поля нашего набора данных. Разберем шаги:

  1. Очищаем или создаем набор данных типа НаборДанныхЗапросСхемыКомпоновкиДанных.
  2. Добавляем поля программно:

НовоеПоле = НаборДанных.Поля.Добавить(Тип("ПолеНабораДанныхСхемыКомпоновкиДанных"));
НовоеПоле.ПутьКДанным = "Контрагент";
НовоеПоле.Поле = "Контрагент";
НовоеПоле.Заголовок = "Клиент";
НовоеПоле.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.Контрагенты");

Этот способ более трудоемкий, но он позволяет строить отчеты на базе абсолютно произвольных структур данных. Для упрощения подобной разработки можно использовать модуль-обёртку над объектной моделью СКД.

Использование внешних наборов данных (Набор данных - Объект)

Иногда запрос проще выполнить отдельно через объект Запрос, получить ТаблицаЗначений, а уже её передать в СКД. Рассмотрим, как это сделать правильно.

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


// Предположим, ТЗ_Данные - это сформированная Таблица Значений
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ВнешняяТаблицаПродаж", ТЗ_Данные);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Передаем структуру внешних наборов во втором параметре метода Инициализировать
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки, Истина);

Важный нюанс: Ключ в структуре ВнешниеНаборыДанных должен символ в символ совпадать с именем объекта, указанным в схеме СКД.

Оптимизация производительности

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

Рекомендации:

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

← На главную