Как исправить ошибку «Поле не найдено» при работе с временными таблицами в запросе 1С?

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

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

Разбор ситуации и анализ ошибки

Рассмотрим сценарий: в модуле объекта документа ОказаниеУслуги выполняется обработчик ОбработкаПроведения. Для расчета остатков и себестоимости используются два последовательных запроса, связанных через МенеджерВременныхТаблиц. Система выдает следующую ошибку:

{Документ.ОказаниеУслуги.МодульОбъекта(70)}: Ошибка при вызове метода контекста (Выполнить) РезультатЗапроса = Запрос2.Выполнить(); по причине: {(5, 24)}: Поле не найдено "НоменклатураДокумента.СуммаВДокументе"

Эта ошибка однозначно указывает на то, что во временной таблице НоменклатураДокумента отсутствует колонка с именем СуммаВДокументе. Чтобы понять причину, нам необходимо проанализировать первый запрос, в котором эта таблица создается и наполняется данными.

Шаг 1: Анализ создания временной таблицы

Давайте посмотрим на исходный код первого запроса, предоставленный автором вопроса:


// Создать менеджер временных таблиц
МенеджерВТ = Новый МенеджерВременныхТаблиц;
Запрос = Новый Запрос;
Запрос.МенеджерВременныхТаблиц = МенеджерВТ;    

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

Проанализируем внимательно секцию ВЫБРАТЬ. Мы видим, что поле Сумма выбирается без псевдонима (алиаса). Это означает, что во временной таблице НоменклатураДокумента колонка будет называться просто Сумма.

Шаг 2: Исправление несоответствия имен полей

Теперь обратимся ко второму запросу, который и вызывает ошибку:


Запрос2 = Новый Запрос;
Запрос2.МенеджерВременныхТаблиц = МенеджерВТ;
Запрос2.Текст = "ВЫБРАТЬ
                |    НоменклатураДокумента.Номенклатура,
                |    НоменклатураДокумента.ВидНоменклатуры,
                |    НоменклатураДокумента.КоличествоВДокументе,
                |    НоменклатураДокумента.СуммаВДокументе,
                ...
                |ИЗ
                |    НоменклатураДокумента КАК НоменклатураДокумента
                ...";

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

Исправленный фрагмент первого запроса должен выглядеть так:


|    СУММА(ОказаниеУслугиПереченьНоменклатуры.Количество) КАК КоличествоВДокументе,
|    ОказаниеУслугиПереченьНоменклатуры.Сумма КАК СуммаВДокументе

Шаг 3: Исправление логической ошибки группировки

При изучении кода первого запроса можно заметить еще одну серьезную проблему, которая приведет к неверным расчетам, даже если ошибка с именем поля исчезнет. Рассмотрим секцию СГРУППИРОВАТЬ ПО:


|СГРУППИРОВАТЬ ПО
|    ОказаниеУслугиПереченьНоменклатуры.Номенклатура,
|    ОказаниеУслугиПереченьНоменклатуры.Номенклатура.ВидНоменклатуры,
|    ОказаниеУслугиПереченьНоменклатуры.Сумма

В документе «Оказание услуги» одна и та же номенклатура может быть введена несколькими строками (например, с разной ценой). Если мы группируем данные по полю Сумма, то строки с одинаковой номенклатурой, но разными суммами не свернутся в одну строку. Это критично для алгоритма списания остатков и расчета себестоимости.

Правильный подход — суммировать значения ресурса. Исправим код первого запроса полностью:


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

Рекомендации по оптимизации и разработке

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

  1. Используйте пакетные запросы. Вместо создания нескольких объектов Запрос и их ручной связки через менеджер временных таблиц, лучше объединить их в один пакетный запрос. В тексте запроса части разделяются символом точки с запятой (;). Это упрощает чтение кода и отладку.
  2. Контроль через Консоль запросов. Перед переносом кода в модуль 1С всегда проверяйте запрос во внешней обработке «Консоль запросов». Это позволит сразу увидеть реальную структуру временных таблиц и типы данных.
  3. Явное указание псевдонимов. Всегда назначайте псевдонимы полям во временных таблицах (через ключевое слово КАК), даже если имя поля совпадает с именем реквизита. Это защитит ваш код от ошибок при изменении структуры метаданных.
  4. Очистка движений перед запросом. В начале обработчика проведения важно записывать пустые наборы записей для регистров, по которым будут читаться остатки (Движения.ИмяРегистра.Записать()). Это гарантирует, что запрос не увидит старые движения этого же документа при перепроведении.
  5. Параметры виртуальных таблиц. При соединении временной таблицы с таблицами остатков (например, РегистрНакопления.ОстаткиМатериалов.Остатки) всегда передавайте в параметры виртуальной таблицы момент времени и условия по измерениям. Это значительно повышает скорость выполнения запроса на больших базах данных.

Разберем пример передачи параметров в виртуальную таблицу:


ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ОстаткиМатериалов.Остатки(&МоментВремени, 
    Материал В (ВЫБРАТЬ Номенклатура ИЗ НоменклатураДокумента)) КАК ОстаткиМатериаловОстатки
ПО НоменклатураДокумента.Номенклатура = ОстаткиМатериаловОстатки.Материал

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

← На главную