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