Разработчики при работе с Системой компоновки данных (СКД) часто сталкиваются с задачей получить тот самый финальный текст запроса, который платформа 1С отправляет в СУБД. Напрямую вытащить его из схемы компоновки данных не получится, так как СКД динамически модифицирует исходный запрос в зависимости от настроек пользователя, установленных отборов, выбранных полей и параметров.
В этой статье мы подробно разберем, почему исходный текст запроса в схеме не совпадает с реальным, как перехватить скомпилированный запрос и его параметры в коде, как правильно обрабатывать схемы с несколькими наборами данных и как программно выгрузить результат компоновки в таблицу значений.
Когда мы пишем запрос в конструкторе макета СКД, мы проектируем лишь "шаблон". В момент формирования отчета СКД выполняет колоссальную работу по оптимизации этого шаблона:
ГДЕ, в параметры виртуальных таблиц или во временные таблицы.ВЫБРАТЬ удаляются все поля, которые не были выбраны пользователем в настройках компоновки и не участвуют в группировках или расчетах ресурсов. Это позволяет существенно снизить нагрузку на базу данных.&Номенклатура) на внутренние идентификаторы (например, &П1, &П2 и так далее).Попытка взять "сырой" запрос из структуры СхемаКомпоновкиДанных.НаборыДанных.ИмяНабора.Запрос приведет к тому, что вы получите исходный неоптимизированный текст без учета пользовательских отборов. Выполнение такого запроса вручную может вызвать зависание системы из-за попытки прочитать миллионы лишних записей.
Для того чтобы отловить сформированные настройки и получить доступ к генерации макета компоновки, лучше всего использовать предопределенную процедуру ПриКомпоновкеРезультата в модуле отчета. В этой точке нам доступны как сама схема, так и текущие настройки пользователя.
Рассмотрим структуру этой процедуры:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартный вывод, если планируем выводить отчет полностью программно
// СтандартнаяОбработка = Ложь;
КонецПроцедуры
Чтобы заставить СКД сгенерировать итоговый текст запроса с учетом всех фильтров, нам необходимо задействовать объект КомпоновщикМакетаКомпоновкиДанных. Именно он транслирует схему компоновки и пользовательские настройки в исполняемый макет.
Разберем по шагам код получения реального текста запроса:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// 1. Получаем настройки отчета с учетом настроек пользователя на форме
НастройкиОтчета = КомпоновщикНастроек.ПолучитьНастройки();
// 2. Инициализируем компоновщик макета компоновки
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// 3. Формируем макет компоновки. На этом этапе СКД компилирует итоговые запросы
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки);
// 4. Обходим все наборы данных, сгенерированные в макете
Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
// Нам интересны только наборы данных типа "Запрос"
Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
ИмяНабора = НаборДанных.Имя;
РеальныйТекстЗапроса = НаборДанных.Запрос;
// Теперь в переменной РеальныйТекстЗапроса находится оптимизированный текст запроса,
// содержащий реальные конструкции ГДЕ и параметры виртуальных таблиц.
ЗаписатьВЛогИлиВывестиВТабло(ИмяНабора, РеальныйТекстЗапроса);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Просто получить текст запроса недостаточно — его невозможно будет запустить без параметров, имена которых СКД изменила. Значения всех параметров также содержатся в сформированном макете компоновки.
Проанализируем ситуацию и напишем код, который перенесет параметры из макета СКД в стандартный объект Запрос:
// Создаем стандартный объект Запрос для последующего выполнения вручную
НовыйЗапрос = Новый Запрос;
НовыйЗапрос.Текст = РеальныйТекстЗапроса; // Используем текст, полученный на предыдущем шаге
// Заполняем параметры запроса из макета компоновки
Для Каждого Параметр Из МакетКомпоновки.ЗначенияПараметров Цикл
// Некоторые параметры могут быть выражениями/формулами СКД, их необходимо вычислить
Если ТипЗнч(Параметр.Значение) = Тип("ВыражениеКомпоновкиДанных") Тогда
ЗначениеПараметра = Вычислить(Параметр.Значение);
Иначе
ЗначениеПараметра = Параметр.Значение;
КонецЕсли;
// Устанавливаем параметры в наш ручной запрос
НовыйЗапрос.УстановитьПараметр(Параметр.Имя, ЗначениеПараметра);
КонецЦикла;
// Теперь этот запрос полностью готов к безопасному и быстрому выполнению!
РезультатЗапроса = НовыйЗапрос.Выполнить();
ТаблицаДанных = РезультатЗапроса.Выгрузить();
Часто в отчетах используется связь нескольких наборов данных (например, Документы, ОсновнаяАналитика и ОборотнаяАналитика). Если они связаны на вкладке "Связи наборов данных" схемы СКД, то важно понимать следующее:
ОсновнаяАналитика без динамически передаваемых параметров связи приведет либо к ошибке нехватки памяти, либо к получению неполных данных.Какое решение применить? Если ваша цель — просто получить готовую таблицу со всеми связями, расчетами ресурсов и группировками, не нужно пытаться эмулировать запросы вручную. Позвольте СКД выполнить всю работу в памяти сервера и выгрузите результат в коллекцию значений.
Этот способ является универсальным, надежным и гарантирует получение абсолютно идентичных данных тем, что пользователь видит на экране своего монитора, без необходимости разбираться во внутренних связях СУБД.
Разберем по шагам, как программно запустить СКД и выгрузить результат в ТаблицаЗначений:
// 1. Инициализируем компоновщик макета и строим макет
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(
СхемаКомпоновкиДанных,
КомпоновщикНастроек.ПолучитьНастройки(),
ДанныеРасшифровки
);
// 2. Инициализируем процессор компоновки данных, который соберет данные из всех наборов
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
// 3. Создаем таблицу значений, в которую будет осуществлен вывод
ТаблицаРезультат = Новый ТаблицаЗначений;
// 4. Используем ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВКоллекциюЗначений;
ПроцессорВывода.УстановитьОбъект(ТаблицаРезультат);
// 5. Выводим результат компоновки в таблицу значений
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Теперь в переменной ТаблицаРезультат содержатся полностью готовые и рассчитанные данные!
Если вам требуется не программное использование запроса в коде конфигурации, а оперативная визуальная отладка "на лету" в режиме предприятия, воспользуйтесь специализированными инструментами:
.erf) или выгруженную схему в формате XML, применить настройки пользователя и нажать кнопку "Анализ исполняемых запросов". Вы увидите точные тексты запросов для каждого набора данных.DBMSSQL (для СУБД Microsoft SQL Server) или SDBL (внутренний язык СУБД 1С) позволит зафиксировать точные запросы, уходящие на уровень базы данных во время формирования вашего отчета.