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

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

При разработке отчетов, печатных форм и алгоритмов обработки данных в 1С часто возникает задача получить сразу несколько дополнительных реквизитов одного объекта (например, документа Увольнение). Однако нередко разработчики сталкиваются с ситуацией: если хотя бы один из дополнительных реквизитов у документа не заполнен, весь запрос возвращает пустой результат (0 строк). Проанализируем, почему так происходит, и разберем несколько надежных способов решения этой проблемы.

Причина проблемы в механизме хранения дополнительных реквизитов

Выясним причину такого поведения платформы. В типовых конфигурациях на базе Библиотеки стандартных подсистем (БСП) табличная часть ДополнительныеРеквизиты хранит только фактически заданные значения. Если пользователь не заполнял дополнительный реквизит или очистил его значение, соответствующая строка физически отсутствует в табличной части объекта базы данных.

Рассмотрим исходный ошибочный запрос:


ВЫБРАТЬ
    УвольнениеДополнительныеРеквизиты.Значение КАК ТрудоваяКнижка
ПОМЕСТИТЬ ВТ_ТрудоваяКнижка
ИЗ
    Документ.Увольнение.ДополнительныеРеквизиты КАК УвольнениеДополнительныеРеквизиты
ГДЕ
    УвольнениеДополнительныеРеквизиты.Ссылка = &Ссылка
    И УвольнениеДополнительныеРеквизиты.Свойство.Наименование = "Трудовая книжка (Увольнения)";

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    УвольнениеДополнительныеРеквизиты.Значение КАК ВкладышТрудовойКнижки,
    ВТ_ТрудоваяКнижка.ТрудоваяКнижка КАК ТрудоваяКнижка
ИЗ
    Документ.Увольнение.ДополнительныеРеквизиты КАК УвольнениеДополнительныеРеквизиты,
    ВТ_ТрудоваяКнижка КАК ВТ_ТрудоваяКнижка
ГДЕ
    УвольнениеДополнительныеРеквизиты.Ссылка = &Ссылка
    И УвольнениеДополнительныеРеквизиты.Свойство.Наименование = "Вкладыш трудовой книжки (Увольнения)"

В этом запросе во втором пакете используется неявное декартово (внутреннее) произведение двух источников: таблицы ДополнительныеРеквизиты и временной таблицы ВТ_ТрудоваяКнижка. Если реквизит «Трудовая книжка» не заполнен, таблица ВТ_ТрудоваяКнижка оказывается пустой. При соединении любой таблицы с пустой таблицей результирующая выборка также становится пустой. Аналогично, если отсутствует «Вкладыш трудовой книжки», секция ГДЕ во втором запросе отсекает все строки, и на выходе мы получаем 0 записей.

Также обратим внимание на условие Свойство.Наименование = ...: обращение через точку к реквизиту Наименование создает неявное соединение с планом видов характеристик ПланВидовХарактеристик.ДополнительныеРеквизитыИСведения, что снижает производительность и делает код уязвимым к переименованию реквизитов пользователями. Рекомендуется передавать ссылки на свойства через параметры запроса.

Способ 1. Использование условных конструкций и группировки (Pivot) — Рекомендуемый

Разберем наиболее эффективный и лаконичный способ получения нескольких дополнительных реквизитов за один шаг без создания лишних временных таблиц. Соединим шапку документа с его табличной частью левым соединением и выполним агрегацию с помощью конструкции МАКСИМУМ(ВЫБОР ...).

Посмотрим на пример запроса:


ВЫБРАТЬ
    ДокументТаблица.Ссылка КАК Ссылка,
    МАКСИМУМ(ВЫБОР
        КОГДА ДопРеквизиты.Свойство = &СвойствоТК
            ТОГДА ДопРеквизиты.Значение
        ИНАЧЕ NULL
    КОНЕЦ) КАК ТрудоваяКнижка,
    МАКСИМУМ(ВЫБОР
        КОГДА ДопРеквизиты.Свойство = &СвойствоВкладыш
            ТОГДА ДопРеквизиты.Значение
        ИНАЧЕ NULL
    КОНЕЦ) КАК ВкладышТрудовойКнижки
ИЗ
    Документ.Увольнение КАК ДокументТаблица
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.Увольнение.ДополнительныеРеквизиты КАК ДопРеквизиты
        ПО ДокументТаблица.Ссылка = ДопРеквизиты.Ссылка
        И ДопРеквизиты.Свойство В (&СвойствоТК, &СвойствоВкладыш)
ГДЕ
    ДокументТаблица.Ссылка = &Ссылка
СГРУППИРОВАТЬ ПО
    ДокументТаблица.Ссылка

Преимущества данного подхода:

  1. Запрос выполняется в один шаг, не создавая временных таблиц в базе TempDB.
  2. Если у документа не заполнен один или даже оба реквизита, запрос гарантированно вернет строку документа с полями, содержащими значение NULL.
  3. Условие по списку свойств вынесено в секцию ПО соединения, что позволяет СУБД отсечь лишние строки до группировки.

Способ 2. Использование временных таблиц и полного соединения

Если логика требует раздельной выборки значений во временные таблицы, для объединения результатов необходимо использовать ПОЛНОЕ СОЕДИНЕНИЕ по ссылке на документ, а также обрабатывать значения NULL функцией ЕСТЬNULL.

Разберем по шагам текст такого запроса:


ВЫБРАТЬ
    ДопРеквизиты.Ссылка КАК Ссылка,
    ДопРеквизиты.Значение КАК ТрудоваяКнижка
ПОМЕСТИТЬ ВТ_ТрудоваяКнижка
ИЗ
    Документ.Увольнение.ДополнительныеРеквизиты КАК ДопРеквизиты
ГДЕ
    ДопРеквизиты.Ссылка = &Ссылка
    И ДопРеквизиты.Свойство = &СвойствоТК
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ДопРеквизиты.Ссылка КАК Ссылка,
    ДопРеквизиты.Значение КАК ВкладышТрудовойКнижки
ПОМЕСТИТЬ ВТ_ВкладышТрудовойКнижки
ИЗ
    Документ.Увольнение.ДополнительныеРеквизиты КАК ДопРеквизиты
ГДЕ
    ДопРеквизиты.Ссылка = &Ссылка
    И ДопРеквизиты.Свойство = &СвойствоВкладыш
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЕСТЬNULL(ТК.Ссылка, ВТК.Ссылка) КАК Ссылка,
    ЕСТЬNULL(ТК.ТрудоваяКнижка, ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)) КАК ТрудоваяКнижка,
    ЕСТЬNULL(ВТК.ВкладышТрудовойКнижки, ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка)) КАК ВкладышТрудовойКнижки
ИЗ
    ВТ_ТрудоваяКнижка КАК ТК
    ПОЛНОЕ СОЕДИНЕНИЕ ВТ_ВкладышТрудовойКнижки КАК ВТК
        ПО ТК.Ссылка = ВТК.Ссылка

Важные нюансы работы с типами значений и функцией ЕСТЬNULL:

  1. В функции ЕСТЬNULL вторым параметром должно передаваться значение по умолчанию, соответствующее типу реквизита. Для дополнительных значений справочника это ЗНАЧЕНИЕ(Справочник.ЗначенияСвойствОбъектов.ПустаяСсылка), для чисел — 0, для дат — ДАТАВРЕМЯ(1, 1, 1).
  2. Если дополнительный реквизит строкового типа имеет неограниченную длину, его необходимо явно приводить к ограниченной длине через ВЫРАЗИТЬ, иначе на уровне СУБД возникнет ошибка соединения или группировки строк неограниченной длины:

ЕСТЬNULL(ВЫРАЗИТЬ(ТК.ТрудоваяКнижка КАК СТРОКА(300)), "") КАК ТрудоваяКнижка

Способ 3. Программное чтение через методы БСП

Если задача решается в модулях конфигурации на встроенном языке 1С, нет необходимости писать прямые запросы к табличным частям. Библиотека стандартных подсистем предоставляет готовый программный интерфейс общего модуля УправлениеСвойствами.

Посмотрим на примеры работы со свойствами:


// Получение одного значения дополнительного реквизита
ЗначениеТК = УправлениеСвойствами.ЗначениеСвойства(СсылкаНаДокумент, СвойствоТК);

// Пакетное чтение значений для объекта
НаборСвойств = Новый Массив;
НаборСвойств.Добавить(СвойствоТК);
НаборСвойств.Добавить(СвойствоВкладыш);

ТаблицаЗначенийСвойств = УправлениеСвойствами.ПрочитатьЗначенияСвойств(СсылкаНаДокумент, НаборСвойств);

Методы БСП автоматически учитывают отсутствие строк в табличной части и корректно возвращают пустые значения или значения по умолчанию без риска получить ошибку выполнения.

← На главную