Почему возникает ошибка «Поле не найдено» при запросе остатков регистра накопления в 1С?

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

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

Анализ типовых ошибок при обращении к виртуальной таблице остатков

Рассмотрим распространенный ошибочный запрос, в котором выбираются поля с теми же именами, что и в структуре регистра:


ВЫБРАТЬ
    РегистрДепозитВодителя.ДепозитИтого,
    РегистрДепозитВодителя.Водитель
ИЗ
    РегистрНакопления.РегистрДепозитВодителя.Остатки(&ВыбДата, Водитель = &ВыбВодитель) КАК РегистрДепозитВодителя

При выполнении такого кода платформа выдаст ошибку:

{(2, 27)}: Поле не найдено "РегистрДепозитВодителя.ДепозитИтого"

Проанализируем ситуацию и выделим три ключевые причины, приводящие к подобным сбоям:

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

Разбираем правильную структуру полей регистра

Чтобы виртуальная таблица остатков работала корректно, проверим структуру регистра в дереве конфигурации:

  1. Поле Водитель должно находиться строго в ветке «Измерения». Только в этом случае по нему будут рассчитываться итоги и к нему можно будет обратиться в запросе остатков.
  2. Поля ДепозитИтого, ДолженВКассуЕЩЕ, СданоВКассу должны располагаться в ветке «Ресурсы».
  3. В виртуальной таблице остатков к ним необходимо обращаться с суффиксом Остаток: ДепозитИтогоОстаток, ДолженВКассуЕЩЕОстаток, СданоВКассуОстаток. К измерению Водитель суффикс не добавляется.

Пошаговое построение корректного запроса остатков

Разберем по шагам, как составить рабочий код запроса с передачей периода и параметров отбора:


&НаСервере
Процедура ПолучитьОстаткиПоВодителю()

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

    // Указываем границу периода для включения движений на крайнюю секунду
    Запрос.УстановитьПараметр(
        "ВыбДата", 
        Новый Граница('20170609235959', ВидГраницы.Включая)
    );
    
    // Передаем ссылку на конкретного водителя
    Запрос.УстановитьПараметр(
        "ВыбВодитель",
        Справочники.Водители.НайтиПоНаименованию("Силкин")
    );    
    
    Результат = Запрос.Выполнить().Выбрать();
    Пока Результат.Следующий() Цикл
        Сообщить(
            "Водитель: " + СокрЛП(Результат.Водитель) +
            " | Депозит: " + Результат.ДепозитИтого +
            " | Должен: " + Результат.ДолженВКассуЕЩЕ +
            " | Сдано: " + Результат.СданоВКассу
        );
    КонецЦикла;

КонецПроцедуры

Оптимизация: параметры виртуальной таблицы против секции «ГДЕ»

Обратим внимание на наложение условий. Условие по измерению всегда следует указывать во втором параметре виртуальной таблицы: Остатки(&Период, Водитель = &ВыбВодитель).

Если написать фильтр в общей секции ГДЕ:


ИЗ
    РегистрНакопления.РегистрДепозитВодителя.Остатки(&ВыбДата) КАК РегистрОстатки
ГДЕ
    РегистрОстатки.Водитель = &ВыбВодитель

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

Особенности передачи момента времени

Выясним разницу между передачей различных типов в параметр периода виртуальной таблицы:

  1. Без указания даты: Если вызвать Остатки() без первого параметра, платформа считает готовые актуальные остатки из таблицы итогов без дополнительных расчетов по таблице движений.
  2. Примитивный тип Дата: Расчет происходит строго на начало секунды. Если передать дату 23:59:59, движения, записанные в эту секунду, в остаток не войдут.
  3. Объект Граница: Конструкция Новый Граница(Дата, ВидГраницы.Включая) принудительно включает в расчет движения, проведенные в указанную секунду.
  4. Момент времени документа: При контроле остатков в момент проведения документа в параметр периода необходимо передавать Ссылка.МоментВремени(), чтобы учесть позицию документа относительно других документов той же секунды.

Использование конструктора запросов

Для предотвращения подобных синтаксических ошибок всегда рекомендуется пользоваться встроенным Конструктором запроса. Конструктор автоматически анализирует метаданные регистра, отображает только доступные для выборки поля с корректными суффиксами (Остаток для ресурсов) и скрывает недоступные реквизиты, исключая возникновение ошибки «Поле не найдено».

← На главную