Почему ПостроительЗапроса не заполняет реквизиты при левом соединении и как это исправить?

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

При разработке отчетов и обработок в 1С мы нередко сталкиваемся с ситуацией, когда запрос прекрасно отрабатывает в Консоли запросов, но при передаче его в объект ПостроительЗапроса часть реквизитов (например, Контрагент или ДоговорКонтрагента) оказывается не заполнена. При этом пустые значения выводятся выборочно, а закономерность на первый взгляд не прослеживается.

Рассмотрим подробно причины возникновения такого поведения парсера Построителя запроса и проанализируем способы решения данной проблемы.

Суть проблемы и механизм ее возникновения

Разберем типичный сценарий построения пакетного запроса, в котором проявляется эта ошибка:

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

В Консоли запросов такой текст выполнится корректно. Однако объект ПостроительЗапроса перед исполнением анализирует и модифицирует исходный текст запроса. Если во второй временной таблице числовой реквизит содержит нулевое значение 0 или NULL, парсер построителя при левом соединении теряет метаданные о типах или ошибочно определяет ветку соединения как нерелевантную. В результате ссылочные поля (контрагенты и договоры) для записей с нулевым значением сбрасываются в пустые ссылки.

Способ 1. Добавление фиктивного непустого реквизита (Быстрый обход)

Простейшим и подтвержденным на практике решением является принудительная активация ветки соединения в парсере Построителя. Для этого добавим во вторую временную таблицу любое фиктивное непустое значение (например, числовую константу 1) и выведем его в итоговую выборку.

Рассмотрим пример формирования первой временной таблицы с фиктивным полем:


ВЫБРАТЬ
    Поставщики.Номенклатура КАК Номенклатура,
    Поставщики.Контрагент КАК Контрагент,
    Поставщики.Отсрочка КАК Отсрочка,
    1 КАК ФиктивноеПоле
ПОМЕСТИТЬ ВТ_Поставщики
ИЗ
    РегистрСведений.ПоставщикиНоменклатуры КАК Поставщики
;

В итоговом запросе выбираем это фиктивное поле вместе со ссылочными реквизитами:


ВЫБРАТЬ
    План.Номенклатура КАК Номенклатура,
    План.Количество КАК Количество,
    ВТ_Поставщики.Контрагент КАК Контрагент,
    ВТ_Поставщики.ФиктивноеПоле КАК ФиктивноеПоле
ИЗ
    ВТ_ПланЗакупок КАК План
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Поставщики КАК ВТ_Поставщики
    ПО План.Номенклатура = ВТ_Поставщики.Номенклатура

Наличие заведомо непустого поля ФиктивноеПоле гарантирует, что ПостроительЗапроса не «отсечет» данную ветку левого соединения и корректно заполнит реквизит Контрагент для всех записей, включая те, у которых отсрочка равна 0.

Способ 2. Явное приведение типов и обработка NULL

Причиной потери полей парсером построителя часто выступает неявное приведение типов данных во временных таблицах. Чтобы исключить неоднозначность типов при соединении таблиц, необходимо использовать функции ЕСТЬNULL и ВЫРАЗИТЬ.

Проанализируем пример явного приведения типов:


ВЫБРАТЬ
    ЕСТЬNULL(ВТ_Поставщики.Контрагент, ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)) КАК Контрагент,
    ВЫРАЗИТЬ(ЕСТЬNULL(ВТ_Поставщики.Отсрочка, 0) КАК Число(10, 0)) КАК Отсрочка
ИЗ
    ВТ_ПланЗакупок КАК План
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Поставщики КАК ВТ_Поставщики
    ПО План.Номенклатура = ВТ_Поставщики.Номенклатура

Явное указание типа возвращаемого значения с помощью ВЫРАЗИТЬ помогает алгоритмам ПостроительЗапроса корректно построить граф зависимостей полей без потери данных.

Способ 3. Использование инструкций Построителя в фигурны скобках

Для явного указания Построителю запроса состава выводимых полей и связей можно применить синтаксис фигурных скобок {}. Это запрещает оптимизатору платформы скрывать или модифицировать поля выборки.

Пример синтаксиса инструкций построителя:


ВЫБРАТЬ
    ВТ_Поставщики.Контрагент КАК Контрагент
{ВЫБРАТЬ
    Контрагент.*}
ИЗ
    ВТ_ПланЗакупок КАК План
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Поставщики КАК ВТ_Поставщики
    ПО План.Номенклатура = ВТ_Поставщики.Номенклатура

Альтернативные архитектурные решения

Объект ПостроительЗапроса является устаревшим механизмом платформы 1С:Предприятие 8, не рассчитанным на сложную работу с пакетными запросами и менеджером временных таблиц. Если в рамках проекта возможно изменение архитектуры, рекомендуется рассмотреть следующие альтернативы:

  1. Переход на Систему Компоновки Данных (СКД): СКД корректно обрабатывает пакетные запросы с левыми соединениями и не искажает типы данных при автоматическом формировании полей.
  2. Использование объекта СхемаЗапроса: Позволяет динамически и безопасно изменять структуру запроса через программный интерфейс платформы 8.3 без риска непредсказуемого парсинга текста.
  3. Использование стандартного объекта Запрос: Формирование текста запроса вручную или с помощью конкатенации строк полностью исключает трансформирование текста платформой.
← На главную