При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда запрос, написанный в конструкторе схемы, существенно отличается от того, что реально выполняется платформой. Особенно остро эта проблема стоит в конфигурации 1С:Зарплата и управление персоналом 3.1, где активно используются так называемые «представления» и программная модификация текста запроса перед выводом. В этой статье мы подробно разберем, как «выловить» итоговый запрос, который учитывает все пользовательские настройки, отборы и программные манипуляции.
Прежде всего, проанализируем важный теоретический момент. Основная ошибка новичков — попытка найти итоговый запрос в объекте СхемаКомпоновкиДанных. Однако схема — это лишь декларативное описание того, «что мы хотим получить». Итоговый же текст, который будет отправлен в СУБД, формируется только в объекте МакетКомпоновкиДанных.
Рассмотрим процесс трансформации данных в СКД:
Если нам нужно увидеть запрос в контексте работающего отчета, наиболее эффективным способом будет использование точки останова в модуле объекта отчета. Разберем по шагам, как это сделать.
Найдем в модуле объекта отчета процедуру ПриКомпоновкеРезультата. В конфигурациях на базе БСП (включая ЗУП) именно здесь происходит основная «магия». Проанализируем типичный фрагмент кода:
Процедура ПриКомпоновкеРезультата(РезультатОформления, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
// Здесь вызываются общие модули, которые могут подменять схему
ЗарплатаКадрыОтчеты.ПриКомпоновкеРезультата(ЭтотОбъект, РезультатОформления, ДанныеРасшифровки, СтандартнаяОбработка);
// Чтобы увидеть итоговый запрос, нам нужно вручную скомпоновать макет
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.ПолучитьНастройки(), ДанныеРасшифровки);
// В переменной МакетКомпоновки теперь содержится итоговый запрос
Для Каждого НаборДанных Из МакетКомпоновки.НаборыДанных Цикл
Если ТипЗнч(НаборДанных) = Тип("НаборДанныхЗапросМакетаКомпоновкиДанных") Тогда
ТекстИтоговогоЗапроса = НаборДанных.Запрос; // Вот он!
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Важный нюанс: Ставьте точку останова ПОСЛЕ вызова общих модулей модификации (например, после ЗарплатаКадрыОтчеты.ПриКомпоновкеРезультата). Именно в этот момент «пустые» запросы-заглушки ЗУПа превращаются в реальный код, работающий с виртуальными таблицами представлений.
Стандартные консоли запросов часто не справляются с отчетами ЗУП, так как не умеют инициализировать специфические параметры или программные обработчики. Рассмотрим использование продвинутых инструментов, таких как «Инструменты разработчика» (автор Tormozit).
Эти инструменты позволяют «подключиться» к уже открытому в пользовательском сеансе отчету. Выясним, почему это удобно:
КомпоновщикНастроек.Если вы используете стороннюю консоль, ищите кнопку «Получить макет компоновки» или «Показать итоговый запрос». Если консоль выдает ошибку в ЗУП, скорее всего, она пытается инициализировать схему в отрыве от программного контекста (общих модулей), который заполняет параметры периодов или описания представлений.
В ЗУП 3.1 текст запроса в СКД часто выглядит крайне лаконично, например: ВЫБРАТЬ * ИЗ Представления_ФИОФизическихЛиц. Это не настоящая таблица, а маркер для программной подстановки.
Разберем, как это работает: СКД при генерации макета вызывает обработчик, который заменяет этот маркер на огромный вложенный запрос с соединениями к регистрам сведений. Чтобы увидеть результат этой замены, недостаточно просто посмотреть СхемаКомпоновкиДанных.НаборыДанных. Нужно обязательно выполнить метод Выполнить() объекта КомпоновщикМакетаКомпоновкиДанных, как было показано в первом методе. Только в Макете маркеры представлений превратятся в реальный SQL-подобный код.
Иногда возникают ситуации, когда запрос в 1С выглядит правильно, но выполняется медленно или возвращает странные результаты из-за особенностей оптимизатора СУБД. Проанализируем, как увидеть «чистый» SQL.
Технологический журнал (ТЖ): Настройте сбор события DBMSSQL (для MS SQL Server) или DBPOSTGRS (для PostgreSQL). Фильтрация по текущему сеансу позволит вам увидеть текст запроса в том виде, в котором его получила база данных. Это крайний, но самый точный метод контроля.
Выясним причину частого вопроса: «Запрос правильный, но при добавлении отбора данные исчезают». Это связано с тем, как СКД модифицирует соединения (JOIN). Рассмотрим ситуацию:
ЛЕВОЕ СОЕДИНЕНИЕ между Таблицей А и Таблицей Б.ЛЕВОЕ СОЕДИНЕНИЕ во ВНУТРЕННЕЕ СОЕДИНЕНИЕ (Inner Join), так как условие на правую таблицу делает левое соединение бессмысленным с точки зрения логики SQL (строки с NULL все равно отсекутся).Чтобы избежать этого, проверьте настройки Ролей полей в СКД. Использование флага Обязательное или правильная настройка условий в секции ГДЕ (с учетом возможных NULL) поможет сохранить ожидаемую структуру запроса при любых пользовательских отборах.
Используя предложенные методы программной отладки и специализированные инструменты, вы всегда сможете точно определить, какой именно запрос выполняет ваша система, и оперативно исправить ошибки в логике компоновки данных.