При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с задачей получения «чистого» SQL-подобного запроса, который платформа 1С:Предприятие отправляет к базе данных. Это необходимо для отладки, оптимизации производительности, выгрузки данных в сторонние системы или выполнения промежуточных расчетов на основе пользовательских фильтров, установленных на форме.
Когда пользователь интерактивно настраивает отборы в элементе КомпоновщикНастройкиОтбор, СКД динамически модифицирует исходный текст запроса: добавляет условия в секцию ГДЕ, параметры и даже может исключать неиспользуемые таблицы. В этой статье мы подробно разберем, как программно передать настройки отбора с формы в СКД и извлечь итоговый результирующий запрос вместе со всеми значениями параметров.
Прежде чем перейти к рабочему коду, проанализируем ситуацию, с которой часто сталкиваются начинающие разработчики (она наглядно представлена в сообщениях 10 и 11 исходной темы форума). При попытке скомпоновать макет свойство МакетКомпоновки.НаборыДанных.Количество() возвращает 0. Выясним, почему это происходит.
В СКД встроен мощный оптимизатор запросов. Если система определяет, что для вывода структуры отчета не требуется никаких полей, она просто не выполняет запрос и полностью исключает наборы данных из итогового макета компоновки. Это происходит в двух случаях:
НовыйСКД, но передаем в компоновщик макета настройки, полученные от другой схемы (например, сохраненной ранее в реквизите формы), оптимизатор не сможет сопоставить поля и «свернет» макет до пустого состояния.Поэтому критически важно следить за тем, чтобы настройки, передаваемые в генератор макета, были получены именно от той схемы, запрос которой мы хотим извлечь, а также содержали как минимум одно выбранное поле или структуру группировки.
Рассмотрим подробнее схему, по которой строится программное извлечение запроса. Процесс состоит из четырех последовательных шагов:
КомпоновщикМакетаКомпоновкиДанных.Запрос для его последующего выполнения.Разберем каждый шаг на практическом примере кода.
Ниже представлен универсальный алгоритм, который корректно обрабатывает как простые запросы, так и сложные наборы данных, содержащие объединения (НаборДанныхОбъединениеМакетаКомпоновкиДанных).
// Шаг 1. Получаем схему СКД и настройки с учетом пользовательских отборов
СхемаКомпоновкиДанных = ПолучитьИзВременногоХранилища(Объект.АдресКомпоновки);
НастройкиСКД = Объект.Компоновщик.ПолучитьНастройки();
// Шаг 2. Инициализируем компоновщик макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// Мы используем стандартный ГенераторМакетаКомпоновкиДанных
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиСКД, , , Тип("ГенераторМакетаКомпоновкиДанных"));
ТекстИтоговогоЗапроса = "";
// Шаг 3. Извлекаем текст запроса из макета
Для Каждого НаборДанныхИзМакета Из МакетКомпоновки.НаборыДанных Цикл
// Если в макете используется стандартный набор данных - запрос
Если ТипЗнч(НаборДанныхИзМакета) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
ТекстИтоговогоЗапроса = НаборДанныхИзМакета.Запрос;
Прервать;
// Если используется объединение нескольких запросов
ИначеЕсли ТипЗнч(НаборДанныхИзМакета) = Тип("НаборДанныхОбъединениеМакетаКомпоновкиДанных") Тогда
Для Каждого ЭлементОбъединения Из НаборДанныхИзМакета.Элементы Цикл
Если ТипЗнч(ЭлементОбъединения) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
// Получаем запрос из первой ветки объединения (или собираем все)
ТекстИтоговогоЗапроса = ЭлементОбъединения.Запрос;
Прервать;
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецЦикла;
В результате переменная ТекстИтоговогоЗапроса будет содержать измененный текст SQL-запроса, в котором платформа уже прописала все необходимые условия связи и фильтрации.
Просто получить текст запроса недостаточно. При интеграции пользовательских отборов СКД заменяет их на автоматически сгенерированные параметры вида &П1, &П2 и так далее. Если попытаться выполнить полученный текст запроса напрямую, платформа выдаст ошибку о неинициализированных параметрах.
Посмотрим на пример того, как правильно перенести все значения параметров из макета компоновки в новый объект Запрос:
Если Не ПустаяСтрока(ТекстИтоговогоЗапроса) Тогда
НовыйЗапрос = Новый Запрос(ТекстИтоговогоЗапроса);
// Заполняем параметры из макета компоновки данных
Для Каждого ПараметрМакета Из МакетКомпоновки.ЗначенияПараметров Цикл
// Некоторые параметры могут быть заданы выражениями СКД (например, "КонецПериода(&Период, ""День"")")
// Их необходимо предварительно вычислить на стороне сервера приложений
Если ТипЗнч(ParaметрМакета.Значение) = Тип("ВыражениеКомпоновкиДанных") Тогда
ЗначениеПараметра = Вычислить(ПараметрМакета.Значение);
Иначе
ЗначениеПараметра = ПараметрМакета.Значение;
КонецЕсли;
НовыйЗапрос.УстановитьПараметр(ПараметрМакета.Имя, ЗначениеПараметра);
КонецЦикла;
// Выполняем запрос и получаем результат
РезультатЗапроса = НовыйЗапрос.Выполнить();
ТаблицаРезультата = РезультатЗапроса.Выгрузить();
КонецЕсли;
При использовании этого механизма важно учитывать несколько неочевидных особенностей поведения платформы 1С:
ВЫБРАТЬ итогового запроса.Автозаполнение у набора данных в состоянии Истина. Это позволяет СКД интеллектуально распределять условия отборов во вложенные запросы и виртуальные таблицы СУБД, что значительно ускоряет выполнение итогового запроса.иробщий.ПолучитьЗапросИзКомпоновкиЛкс()).Применяя описанный подход, вы сможете гибко управлять генерацией запросов, учитывая любые сложные отборы, группировки и параметры, которые пользователи устанавливают на управляемых формах ваших прикладных решений.