В процессе разработки на платформе 1С:Предприятие часто возникает задача динамического получения цен. Например, когда для каждой позиции номенклатуры в её реквизитах указан свой «Вид цены», по которому должна производиться выгрузка. Однако при попытке реализовать это «в лоб» через параметры виртуальной таблицы, разработчики сталкиваются с ошибкой: «Поле не найдено...». Разберем детально, почему это происходит и как правильно составить такой запрос.
Рассмотрим ситуацию: в справочнике Номенклатура создан новый реквизит ЦенаВыгрузкиНаСайт с типом СправочникСсылка.ВидыЦен. Нам необходимо получить актуальную цену для каждой позиции, используя именно тот вид цены, который закреплен за конкретной карточкой товара.
Типичная ошибка в тексте запроса выглядит следующим образом:
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ТекДата, ВидЦены = СпрНоменклатура.ЦенаВыгрузкиНаСайт) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СпрНоменклатура.Ссылка)
Система выдает ошибку: Поле не найдено "СпрНоменклатура.ЦенаВыгрузкиНаСайт". Проанализируем причину. Виртуальные таблицы (такие как СрезПоследних) не являются физическими таблицами в базе данных SQL. При выполнении запроса платформа 1С транслирует обращение к виртуальной таблице во вложенный подзапрос (Subquery).
Область видимости и изоляция: Вложенный подзапрос, формирующий срез последних записей, выполняется «внутри» себя и на этом этапе ничего не знает о внешних таблицах, которые участвуют в основном запросе (в нашем случае — о таблице Справочник.Номенклатура). Поскольку соединение (JOIN) происходит только после формирования выборок из таблиц, обращение к полю СпрНоменклатура.ЦенаВыгрузкиНаСайт внутри параметров виртуальной таблицы синтаксически недопустимо.
Самый быстрый способ исправить ошибку — это убрать условие из параметров виртуальной таблицы и перенести его в условия связи ЛЕВОЕ СОЕДИНЕНИЕ ... ПО. Выясним, как изменится структура запроса:
ПО.Посмотрим на исправленный пример кода:
ВЫБРАТЬ
СпрНоменклатура.Ссылка,
СпрНоменклатура.Наименование,
ЕСТЬNULL(ЦеныНоменклатурыСрезПоследних.Цена, 0) КАК Цена
ИЗ
Справочник.Номенклатура КАК СпрНоменклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ТекДата, ) КАК ЦеныНоменклатурыСрезПоследних
ПО (ЦеныНоменклатурыСрезПоследних.Номенклатура = СпрНоменклатура.Ссылка)
И (ЦеныНоменклатурыСрезПоследних.ВидЦены = СпрНоменклатура.ЦенаВыгрузкиНаСайт)
ГДЕ
СпрНоменклатура.Ссылка В ИЕРАРХИИ(&ГруппаНоменклатуры)
В данном случае запрос отработает успешно. Однако здесь скрыт важный нюанс производительности. Если в регистре сведений ЦеныНоменклатуры хранятся десятки видов цен для каждой номенклатуры, виртуальная таблица СрезПоследних без параметров сначала получит все последние цены по всем видам цен, а затем механизм соединения отсечет лишние. При больших объемах данных это может замедлить работу системы.
Если производительность критична (например, выгрузка сотен тысяч позиций), профессиональным подходом будет использование временных таблиц. Разберем этот метод по шагам:
Номенклатура и ВидЦены.Проанализируем пример такого подхода:
// Шаг 1: Подготовка данных
ВЫБРАТЬ
СпрНоменклатура.Ссылка КАК Ссылка,
СпрНоменклатура.ЦенаВыгрузкиНаСайт КАК ВидЦены
ПОМЕСТИТЬ ВТ_НужнаяНоменклатура
ИЗ
Справочник.Номенклатура КАК СпрНоменклатура
ГДЕ
СпрНоменклатура.Ссылка В ИЕРАРХИИ(&ГруппаНоменклатуры)
ИНДЕКСИРОВАТЬ ПО
Ссылка,
ВидЦены
;
// Шаг 2: Получение цен
ВЫБРАТЬ
ВТ.Ссылка,
ЕСТЬNULL(Цены.Цена, 0) КАК Цена
ИЗ
ВТ_НужнаяНоменклатура КАК ВТ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&ТекДата,
(Номенклатура, ВидЦены) В (ВЫБРАТЬ Ссылка, ВидЦены ИЗ ВТ_НужнаяНоменклатура)) КАК Цены
ПО ВТ.Ссылка = Цены.Номенклатура И ВТ.ВидЦены = Цены.ВидЦены
Использование конструкции (Номенклатура, ВидЦены) В (ВЫБРАТЬ ...) в параметрах виртуальной таблицы позволяет платформе максимально эффективно ограничить выборку на уровне СУБД, используя индексы регистра.
Разберем еще несколько важных моментов, которые помогут избежать ошибок в будущем:
Индексация нового реквизита: Когда мы добавляем в справочник Номенклатура новый реквизит (например, ЦенаВыгрузкиНаСайт) и планируем использовать его в условиях запроса или связях, крайне важно в конфигураторе установить свойство «Индексировать». Без индекса поиск по этому полю будет вызывать полное сканирование таблицы (Full Scan), что приведет к деградации производительности при росте справочника.
Обработка пустых значений (NULL): При использовании ЛЕВОЕ СОЕДИНЕНИЕ всегда помните о том, что для некоторых позиций цена может быть не установлена. Использование функции ЕСТЬNULL(Поле, 0) — хороший тон, позволяющий избежать ошибок при дальнейших арифметических операциях с результатом запроса.
Работа с табличными частями: В исходном вопросе автор обращался к табличной части ДополнительныеРеквизиты прямо в основном запросе. Помните, что такой синтаксис (вложенная выборка через точку) эффективно работает при выгрузке в РезультатЗапроса, но при использовании в СКД может привести к дублированию строк в группировках. Рекомендуется выбирать табличные части отдельными запросами во временные таблицы.
Подведем итог: ошибка «Поле не найдено» — это сигнал о том, что вы пытаетесь передать контекст одной таблицы туда, где он еще недоступен. Используйте перенос условий в секцию ПО для простых задач или временные таблицы для сложных и нагруженных систем.