Почему возникает ошибка «Поле не найдено» при обращении к реквизиту номенклатуры в параметрах виртуальной таблицы?

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

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

Анализ проблемы и поиск причины ошибки

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

Типичная ошибка в тексте запроса выглядит следующим образом:


ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ТекДата, ВидЦены = СпрНоменклатура.ЦенаВыгрузкиНаСайт) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СпрНоменклатура.Ссылка)

Система выдает ошибку: Поле не найдено "СпрНоменклатура.ЦенаВыгрузкиНаСайт". Проанализируем причину. Виртуальные таблицы (такие как СрезПоследних) не являются физическими таблицами в базе данных SQL. При выполнении запроса платформа 1С транслирует обращение к виртуальной таблице во вложенный подзапрос (Subquery).

Область видимости и изоляция: Вложенный подзапрос, формирующий срез последних записей, выполняется «внутри» себя и на этом этапе ничего не знает о внешних таблицах, которые участвуют в основном запросе (в нашем случае — о таблице Справочник.Номенклатура). Поскольку соединение (JOIN) происходит только после формирования выборок из таблиц, обращение к полю СпрНоменклатура.ЦенаВыгрузкиНаСайт внутри параметров виртуальной таблицы синтаксически недопустимо.

Решение №1: Перенос условия в секцию ПО

Самый быстрый способ исправить ошибку — это убрать условие из параметров виртуальной таблицы и перенести его в условия связи ЛЕВОЕ СОЕДИНЕНИЕ ... ПО. Выясним, как изменится структура запроса:

  1. Очистим параметры виртуальной таблицы от ссылок на поля других таблиц.
  2. Добавим проверку соответствия вида цены в блоке ПО.

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


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

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

Решение №2: Оптимизация через использование временных таблиц

Если производительность критична (например, выгрузка сотен тысяч позиций), профессиональным подходом будет использование временных таблиц. Разберем этот метод по шагам:

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

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


// Шаг 1: Подготовка данных
ВЫБРАТЬ
    СпрНоменклатура.Ссылка КАК Ссылка,
    СпрНоменклатура.ЦенаВыгрузкиНаСайт КАК ВидЦены
ПОМЕСТИТЬ ВТ_НужнаяНоменклатура
ИЗ
    Справочник.Номенклатура КАК СпрНоменклатура
ГДЕ
    СпрНоменклатура.Ссылка В ИЕРАРХИИ(&ГруппаНоменклатуры)
ИНДЕКСИРОВАТЬ ПО
    Ссылка,
    ВидЦены
;

// Шаг 2: Получение цен
ВЫБРАТЬ
    ВТ.Ссылка,
    ЕСТЬNULL(Цены.Цена, 0) КАК Цена
ИЗ
    ВТ_НужнаяНоменклатура КАК ВТ
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ТекДата, 
        (Номенклатура, ВидЦены) В (ВЫБРАТЬ Ссылка, ВидЦены ИЗ ВТ_НужнаяНоменклатура)) КАК Цены
    ПО ВТ.Ссылка = Цены.Номенклатура И ВТ.ВидЦены = Цены.ВидЦены

Использование конструкции (Номенклатура, ВидЦены) В (ВЫБРАТЬ ...) в параметрах виртуальной таблицы позволяет платформе максимально эффективно ограничить выборку на уровне СУБД, используя индексы регистра.

Дополнительные рекомендации по работе с реквизитами в запросах

Разберем еще несколько важных моментов, которые помогут избежать ошибок в будущем:

Индексация нового реквизита: Когда мы добавляем в справочник Номенклатура новый реквизит (например, ЦенаВыгрузкиНаСайт) и планируем использовать его в условиях запроса или связях, крайне важно в конфигураторе установить свойство «Индексировать». Без индекса поиск по этому полю будет вызывать полное сканирование таблицы (Full Scan), что приведет к деградации производительности при росте справочника.

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

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

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

← На главную