Как получить реальный текст запроса с учетом отборов из СКД?

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

При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с задачей получения «чистого» SQL-подобного запроса, который платформа 1С:Предприятие отправляет к базе данных. Это необходимо для отладки, оптимизации производительности, выгрузки данных в сторонние системы или выполнения промежуточных расчетов на основе пользовательских фильтров, установленных на форме.

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

Выясняем причину: почему МакетКомпоновки.НаборыДанных пуст?

Прежде чем перейти к рабочему коду, проанализируем ситуацию, с которой часто сталкиваются начинающие разработчики (она наглядно представлена в сообщениях 10 и 11 исходной темы форума). При попытке скомпоновать макет свойство МакетКомпоновки.НаборыДанных.Количество() возвращает 0. Выясним, почему это происходит.

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

  1. В настройках компоновки не выбрано ни одно поле и отсутствует структура группировок (детальных записей).
  2. Несоответствие настроек и схемы компоновки. Если мы программно создаем новую схему НовыйСКД, но передаем в компоновщик макета настройки, полученные от другой схемы (например, сохраненной ранее в реквизите формы), оптимизатор не сможет сопоставить поля и «свернет» макет до пустого состояния.

Поэтому критически важно следить за тем, чтобы настройки, передаваемые в генератор макета, были получены именно от той схемы, запрос которой мы хотим извлечь, а также содержали как минимум одно выбранное поле или структуру группировки.

Пошаговый алгоритм получения результирующего запроса

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

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

Разберем каждый шаг на практическом примере кода.

Реализация программного кода для извлечения запроса

Ниже представлен универсальный алгоритм, который корректно обрабатывает как простые запросы, так и сложные наборы данных, содержащие объединения (НаборДанныхОбъединениеМакетаКомпоновкиДанных).


// Шаг 1. Получаем схему СКД и настройки с учетом пользовательских отборов
СхемаКомпоновкиДанных = ПолучитьИзВременногоХранилища(Объект.АдресКомпоновки);
НастройкиСКД = Объект.Компоновщик.ПолучитьНастройки();

// Шаг 2. Инициализируем компоновщик макета
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;

// Мы используем стандартный ГенераторМакетаКомпоновкиДанных
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиСКД, , , Тип("ГенераторМакетаКомпоновкиДанных"));

ТекстИтоговогоЗапроса = "";

// Шаг 3. Извлекаем текст запроса из макета
Для Каждого НаборДанныхИзМакета Из МакетКомпоновки.НаборыДанных Цикл
    
    // Если в макете используется стандартный набор данных - запрос
    Если ТипЗнч(НаборДанныхИзМакета) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
        ТекстИтоговогоЗапроса = НаборДанныхИзМакета.Запрос;
        Прервать; 
        
    // Если используется объединение нескольких запросов
    ИначеЕсли ТипЗнч(НаборДанныхИзМакета) = Тип("НаборДанныхОбъединениеМакетаКомпоновкиДанных") Тогда
        Для Каждого ЭлементОбъединения Из НаборДанныхИзМакета.Элементы Цикл
            Если ТипЗнч(ЭлементОбъединения) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
                // Получаем запрос из первой ветки объединения (или собираем все)
                ТекстИтоговогоЗапроса = ЭлементОбъединения.Запрос;
                Прервать;
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
    
КонецЦикла;

В результате переменная ТекстИтоговогоЗапроса будет содержать измененный текст SQL-запроса, в котором платформа уже прописала все необходимые условия связи и фильтрации.

Перенос параметров и выполнение результирующего запроса

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

Посмотрим на пример того, как правильно перенести все значения параметров из макета компоновки в новый объект Запрос:


Если Не ПустаяСтрока(ТекстИтоговогоЗапроса) Тогда

    НовыйЗапрос = Новый Запрос(ТекстИтоговогоЗапроса);
    
    // Заполняем параметры из макета компоновки данных
    Для Каждого ПараметрМакета Из МакетКомпоновки.ЗначенияПараметров Цикл
        
        // Некоторые параметры могут быть заданы выражениями СКД (например, "КонецПериода(&Период, ""День"")")
        // Их необходимо предварительно вычислить на стороне сервера приложений
        Если ТипЗнч(ParaметрМакета.Значение) = Тип("ВыражениеКомпоновкиДанных") Тогда
            ЗначениеПараметра = Вычислить(ПараметрМакета.Значение);
        Иначе
            ЗначениеПараметра = ПараметрМакета.Значение;
        КонецЕсли;
        
        НовыйЗапрос.УстановитьПараметр(ПараметрМакета.Имя, ЗначениеПараметра);
        
    КонецЦикла;
    
    // Выполняем запрос и получаем результат
    РезультатЗапроса = НовыйЗапрос.Выполнить();
    ТаблицаРезультата = РезультатЗапроса.Выгрузить();
    
КонецЕсли;

Важные нюансы работы оптимизатора СКД

При использовании этого механизма важно учитывать несколько неочевидных особенностей поведения платформы 1С:

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

← На главную