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

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

При разработке отчетов на Системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда один и тот же запрос в консоли запросов возвращает корректные данные, а в СКД — пустую таблицу. Особенно часто это происходит при использовании пакетных запросов с временными таблицами (ВТ) и виртуальными таблицами остатков или оборотов. Разберем эту проблему подробно, выясним причины и рассмотрим несколько способов ее решения.

Анализируем причину: Коварство оптимизатора СКД

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

Если в настройках отчета (в пользовательском режиме или в схеме) не выбраны поля из какой-либо таблицы, участвующей в запросе, СКД может посчитать эту таблицу лишней и просто удалить её из итогового текста запроса. В случае с временными таблицами это выглядит так: вы помещаете данные во временную таблицу Реализации, а в основном запросе используете условие ГДЕ Ссылка В (ВЫБРАТЬ Ссылка ИЗ Реализации). Если поле Ссылка из этой ВТ больше нигде не задействовано как выбранное поле или ресурс, оптимизатор решит, что вся временная таблица не нужна для получения итогового результата, и «вырежет» её. В итоге условие В (...) будет ссылаться на несуществующие данные или трансформироваться в пустой результат.

Рассмотрим пример запроса, который может вызывать проблему:


ВЫБРАТЬ
    РасчетыОстаткиИОбороты.ЗаказКлиента КАК Ссылка,
    РасчетыОстаткиИОбороты.ДолгКонечныйОстаток
ПОМЕСТИТЬ Реализации
ИЗ
    РегистрНакопления.РасчетыСКлиентамиПоДокументам.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ) КАК РасчетыОстаткиИОбороты
ГДЕ
    РасчетыОстаткиИОбороты.ДолгКонечныйОстаток = 0;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    РеализацияТовары.Ссылка КАК Регистратор,
    РеализацияТовары.Номенклатура
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
ГДЕ
    РеализацияТовары.Ссылка В (ВЫБРАТЬ Реализации.Ссылка ИЗ Реализации)

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

Решение 1: Свойство «Обязательное» для полей

Самый простой и правильный способ «подсказать» СКД, что поле (и, соответственно, таблица) должно присутствовать в запросе в любом случае — это использование флага Обязательное.

Рассмотрим, как это сделать по шагам:

  1. Откроем схему компоновки данных и перейдем на закладку Наборы данных.
  2. В списке полей найдем то поле, которое мы выбираем из временной таблицы (в нашем примере это Ссылка из ВТ Реализации).
  3. В колонке Обязательное установим галочку. Это заставит СКД всегда включать данное поле в итоговый SQL-запрос, даже если пользователь не выбрал его для отображения в отчете.

Важно помнить: если у вас пакетный запрос, это свойство нужно проверять для полей того набора данных, который является «источником» для условий в последующих пакетах.

Решение 2: Замена подзапроса на внутреннее соединение

Опыт показывает, что СКД гораздо корректнее обрабатывает Внутренние соединения (INNER JOIN), чем условия с конструкцией В (ВЫБРАТЬ...). Для системы соединение — это явный признак связи двух таблиц, который оптимизатору сложнее игнорировать.

Перепишем наш пример, заменив условие на соединение:


ВЫБРАТЬ
    РасчетыОстаткиИОбороты.ЗаказКлиента КАК Ссылка
ПОМЕСТИТЬ Реализации
ИЗ
    РегистрНакопления.РасчетыСКлиентамиПоДокументам.ОстаткиИОбороты(&НачалоПериода, &КонецПериода, , , ) КАК РасчетыОстаткиИОбороты
ГДЕ
    РасчетыОстаткиИОбороты.ДолгКонечныйОстаток = 0
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    РеализацияТовары.Ссылка КАК Регистратор,
    РеализацияТовары.Номенклатура
ИЗ
    Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТовары
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ Реализации КАК ВТ_Реализации
    ПО РеализацияТовары.Ссылка = ВТ_Реализации.Ссылка

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

Решение 3: Параметры виртуальных таблиц и фигурные скобки

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

Рекомендуется использовать стандартный синтаксис СКД для параметров:


ИЗ
    РегистрНакопления.РасчетыСКлиентамиПоДокументам.ОстаткиИОбороты({&НачалоПериода}, {&КонецПериода}, , , ) КАК РасчетыОстаткиИОбороты

Это позволит системе компоновки данных гибко управлять периодом и корректно передавать значения из стандартных настроек «Период» в текст запроса.

Решение 4: Проверка прав доступа

Иногда причина кроется не в коде, а в правах доступа (RLS). Выясним, нет ли у пользователя ограничений на чтение документов или регистров, используемых в запросе. СКД работает «молча»: если у пользователя нет прав на какую-то таблицу или даже на одно поле составного типа (например, поле Регистратор в регистре), компоновщик может просто исключить это поле или всю таблицу из запроса без выдачи ошибок. В консоли запросов под полными правами всё будет работать, а у пользователя в отчете — нет.

Проверьте права на:

Как убедиться, что проблема в оптимизации?

Чтобы окончательно развеять сомнения, мы можем просмотреть исполняемый запрос, который генерирует СКД. Для этого можно воспользоваться внешними обработками (например, «Консоль компоновки данных») или включить Технологический журнал.

Если в исполняемом запросе вы видите, что секция ПОМЕСТИТЬ отсутствует или из неё удалены все важные фильтры — значит, вы столкнулись именно с оптимизацией. В таком случае возвращаемся к Решению 1 (Обязательные поля) или Решению 2 (Соединения).

Резюме: Чтобы ваш запрос в СКД работал так же стабильно, как в консоли, избегайте скрытых зависимостей. Делайте связи между таблицами явными через соединения и используйте флаг «Обязательное» для ключевых полей связи во временных таблицах.

← На главную