Как правильно получить значение дополнительного реквизита в запросе 1С и почему возвращается 0?

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

При разработке запросов в системе 1С:Предприятие 8 программисты часто сталкиваются с ситуацией, когда данные, полученные в «Консоли запросов», не совпадают с результатами работы программного кода. Типичный пример — получение значения дополнительного реквизита (например, «Приоритет склада»). В консоли мы видим число, а в коде при выгрузке в Таблицу Значений или при обходе выборки вместо ожидаемого результата получаем 0 или пустое значение. Разберем подробно, почему это происходит и как правильно составить запрос для получения плоских данных.

Причина ошибки: механизм вложенных таблиц (Nested Tables)

Проанализируем конструкцию запроса, которую часто используют новички: Остатки.Склад.ДополнительныеРеквизиты.Значение. В объектной модели 1С дополнительные реквизиты хранятся в табличной части объекта (в данном случае справочника Склады). Когда в секции ВЫБРАТЬ мы обращаемся к табличной части через точку, платформа 1С ведет себя не так, как классическая СУБД SQL.

Рассмотрим ситуацию подробнее. Вместо того чтобы вернуть конкретное значение, платформа формирует вложенную таблицу для каждой строки основного результата. Это означает, что в колонке «Приоритет» у вас оказывается не число 1 или 2, а объект типа РезультатЗапроса. По сути, внутри одной ячейки вашей выборки лежит еще одна маленькая таблица, содержащая все строки из табличной части доп. реквизитов данного склада.

Почему Консоль запросов показывает число?
Это один из самых коварных моментов. Разработчики консолей запросов программно обрабатывают такие поля. Если консоль видит в ячейке вложенную таблицу, она автоматически берет значение из первой строки первой колонки этой таблицы и отображает его пользователю. Это создает иллюзию того, что запрос возвращает простое значение, хотя на самом деле структура данных гораздо сложнее.

Почему в коде получается 0?
Когда вы программно пытаетесь присвоить объект РезультатЗапроса (вложенную таблицу) колонке в Таблице Значений, имеющей тип Число, система пытается выполнить приведение типов. Так как объект коллекции не может быть преобразован в число, срабатывает значение по умолчанию — 0.

Решение №1: Использование явного левого соединения (Рекомендуемый способ)

Чтобы получить «плоский» результат, где в каждой строке будет конкретное значение реквизита, необходимо отказаться от обращения к табличной части через точку в секции ВЫБРАТЬ. Вместо этого мы используем конструкцию ЛЕВОЕ СОЕДИНЕНИЕ с таблицей дополнительных реквизитов.

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


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

Проанализируем, что мы изменили в этой конструкции:

  1. Явное соединение: Мы обратились к таблице Справочник.Склады.ДополнительныеРеквизиты. В базе данных 1С табличные части хранятся в отдельных физических таблицах SQL, где поле Ссылка связывает строку ТЧ с владельцем.
  2. Фильтрация по свойству: В условии соединения мы указали СвойствоПриоритет.Свойство = &ПараметрСвойствоПриоритет. Это критически важно. Если у склада несколько дополнительных реквизитов, без этого условия строки в результате запроса «размножатся» (произойдет декартово произведение по количеству реквизитов).
  3. Обработка NULL: Мы использовали функцию ЕСТЬNULL. Если у склада не задан доп. реквизит «Приоритет», левое соединение вернет NULL. Данная функция заменит его на 0, что позволит избежать ошибок при дальнейших математических операциях в коде.

Решение №2: Выражение типов (ВЫРАЗИТЬ)

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

Для гарантированного получения числа используем ВЫРАЗИТЬ:


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

Это обеспечит создание в результирующей ТаблицеЗначений колонки с типом Число, а не Произвольный тип.

Особенности работы секции ГДЕ при обращении к ТЧ

Выясним еще одну важную деталь, которая часто путает разработчиков. Рассмотрим условие ГДЕ Остатки.Склад.ДополнительныеРеквизиты.Свойство = &СкладИМ.

Когда вы пишете такое условие в секции ГДЕ, 1С транслирует это в SQL-запрос с использованием оператора EXISTS или неявного внутреннего соединения. Это работает как фильтр: «Выбрать только те склады, у которых в списке дополнительных реквизитов есть хотя бы одна строка с таким-то свойством».

Важно понимать: использование точки в секции ГДЕ никак не влияет на то, что вы получите в секции ВЫБРАТЬ. Если вы в ГДЕ отфильтровали склады по наличию реквизита, но в ВЫБРАТЬ все еще используете Остатки.Склад.ДополнительныеРеквизиты.Значение, вы все равно получите вложенную таблицу, а не число.

Подведем итоги и сформируем лучшие практики

Для эффективной работы с дополнительными реквизитами и сведениями в 1С рекомендуем придерживаться следующих правил:

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

← На главную