При разработке сложных отчетов в системе компоновки данных (СКД) разработчики часто сталкиваются с ситуацией, когда запрос, идеально работающий в обычной консоли запросов, в отчете СКД возвращает пустые поля, не выводит нужные строки или ведет себя некорректно. Разберем причины такого поведения платформы 1С:Предприятие и рассмотрим по шагам, как исправить эту проблему.
Главная причина расхождения между результатом консоли запросов и отчетом на СКД заключается в работе встроенного оптимизатора СКД:
Автозаполнение компоновщик анализирует только те поля, которые выбраны в текущих группировках, колонках или отборах настроек отчета. Если промежуточное поле во временной таблице используется только в условии соединения или подзапросе вида ГДЕ Поле В (ВЫБРАТЬ ...), оптимизатор СКД может ошибочно посчитать его лишним и вырезать из итогового запроса.Регистр.ОстаткиИОбороты(..., ЗаказКлиента В (ВЫБРАТЬ ...))) затрудняет для СКД построение графа связей. В результате связующие поля во временных таблицах удаляются, что приводит к разрушению логики соединений.ВЫБРАТЬ ... ИЗ (ВЫБРАТЬ ...) не позволяет применить конструкцию РАЗРЕШЕННЫЕ внутри вложенного запроса. Это вызывает ошибки доступа или вывод «Объект не найден» у пользователей с неполными правами. При переходе на пакет запросов с временными таблицами синтаксис ВЫБРАТЬ РАЗРЕШЕННЫЕ становится доступным, но вмешивается оптимизатор СКД.Самый простой и надежный способ защитить поля и временные таблицы от удаления оптимизатором — явно указать платформе, что они обязательны для выполнения запроса.
Выполним следующие шаги:
ЗаказКлиента) через все промежуточные временные таблицы до финальной выборки.ВТЗаказы, ВТПродажи).Оптимизатор СКД значительно лучше обрабатывает явные соединения между таблицами, чем конструкции В (ВЫБРАТЬ ...) в параметрах виртуальных таблиц. Перепишем выборку с использованием явных левых и внутренних соединений.
Посмотрим на пример рефакторинга финального пакета запроса:
ВЫБРАТЬ
ЗаказыКлиентовОстаткиИОбороты.ЗаказКлиента КАК ЗаказКлиента,
ИСТИНА КАК ПолностьюОтгружен,
ЗаказыКлиентовОстаткиИОбороты.ЗаказаноРасход КАК ЗаказаноРасход
ПОМЕСТИТЬ ВТ
ИЗ
РегистрНакопления.ЗаказыКлиентов.ОстаткиИОбороты(&ДатаНач, &ДатаКон, , , ) КАК ЗаказыКлиентовОстаткиИОбороты
ГДЕ
ЗаказыКлиентовОстаткиИОбороты.ЗаказаноКонечныйОстаток = 0
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
РасчетыСКлиентамиОбороты.ЗаказКлиента,
ЛОЖЬ,
0
ИЗ
РегистрНакопления.РасчетыСКлиентами.Обороты(&ДатаНач, &ДатаКон, , ЗаказКлиента ССЫЛКА Документ.ЗаказКлиента) КАК РасчетыСКлиентамиОбороты
ГДЕ
РасчетыСКлиентамиОбороты.СуммаРасход > 0
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.ЗаказКлиента КАК ЗаказКлиента,
МАКСИМУМ(ВТ.ПолностьюОтгружен) КАК ПолностьюОтгружен,
СУММА(ВТ.ЗаказаноРасход) КАК ЗаказаноРасход
ПОМЕСТИТЬ ВТЗаказы
ИЗ
ВТ КАК ВТ
СГРУППИРОВАТЬ ПО
ВТ.ЗаказКлиента
ИНДЕКСИРОВАТЬ ПО
ЗаказКлиента
;
Далее соединяем полученную таблицу ВТЗаказы через ВНУТРЕННЕЕ СОЕДИНЕНИЕ напрямую с виртуальными таблицами вместо использования громоздких условий ГДЕ ЗаказКлиента В (ВЫБРАТЬ ...).
Если оптимизатор СКД продолжает искажать итоговый текст запроса, отключим автоматическую модификацию:
{ВЫБРАТЬ ...}, {ГДЕ ...}.Для крайне сложных и разветвленных отчетов с большим количеством условий и расчетов имеет смысл перенести выполнение запроса в программный модуль:
МенеджерВременныхТаблиц, после чего передаем менеджер в процессор компоновки данных:
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборы, ДанныеРасшифровки, Истина, , МенеджерВТ);
Запрос, выгружаем итоговый результат в ТаблицаЗначений и передаем ее в СКД через коллекцию ВнешниеНаборыДанных.Чтобы точно увидеть, как именно СКД модифицирует исходный запрос, воспользуемся специализированными инструментами (например, подсистемой Инструменты разработчика) или получим реальный выполняемый текст запроса программно из объекта МакетКомпоновкиДанных. Это позволит мгновенно определить, какое именно поле или временная таблица были вырезаны оптимизатором.