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

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

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

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

Анализ исходной ситуации и причины ошибки

Рассмотрим типовой запрос динамического списка, создающий проблему:


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

Выясним причину падения: поддержка пакетных запросов и конструкции ПОМЕСТИТЬ в динамических списках появилась только начиная с версии платформы 8.3.8. Если конфигурация работает с включенным режимом совместимости ниже 8.3.8 (например, Режим совместимости с версией 8.2.16 в старых редакциях УТ 11.0, КА 2.0 или самописных базах), механизм парсинга динамического списка не умеет корректно обрабатывать пакетные выборки и извлекать структуру финальных полей. В результате система считает, что результирующие поля отсутствуют, и генерирует исключение «Поле не найдено».

Решение 1. Замена временных таблиц на вложенные подзапросы

Если повышение режима совместимости конфигурации невозможно или нежелательно, перепишем запрос без использования пакетного разделения ПОМЕСТИТЬ ... ;, заменив временные таблицы на вложенные запросы в секциях соединения. Вложенные запросы полностью поддерживаются динамическими списками во всех режимах совместимости платформы 1С.

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


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

Обратим внимание на применение функции ЕСТЬNULL: при левом соединении для подразделений, по которым не было движений или остатков, возвращается значение NULL, что может приводить к некорректным результатам при вычислении условий в секции ГДЕ.

Решение 2. Корректная установка параметров динамического списка

В тексте запроса присутствуют параметры виртуальных таблиц &НачалоПериода и &КонецПериода. Если эти параметры не переданы до первой компоновки списка на сервере, список также не сможет отобразить данные. Проинициализируем параметры в обработчике формы ПриСозданииНаСервере:


&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    
    // Установка параметров динамического списка
    Список.Параметры.УстановитьЗначениеПараметра("НачалоПериода", НачалоДня(ТекущаяДатаСеанса()));
    Список.Параметры.УстановитьЗначениеПараметра("КонецПериода", КонецДня(ТекущаяДатаСеанса()));
    
КонецПроцедуры

Решение 3. Использование таблицы значений вместо динамического списка

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

Разберем по шагам альтернативный и более устойчивый подход:

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

Посмотрим на реализацию серверной процедуры загрузки данных:


&НаСервере
Процедура ОбновитьСводкуНаСервере()
    
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   ВыручкаОбороты.Подразделение КАК Подразделение,
        |   ВыручкаОбороты.СуммаВыручкиОборот КАК СуммаВыручкиОборот
        |ПОМЕСТИТЬ втВыручка
        |ИЗ
        |   РегистрНакопления.ВыручкаИСебестоимостьПродаж.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ВыручкаОбороты
        |;
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |   ДСОстатки.Касса.Подразделение КАК Подразделение,
        |   ДСОстатки.СуммаОстаток КАК СуммаОстаток
        |ПОМЕСТИТЬ втДС
        |ИЗ
        |   РегистрНакопления.ДенежныеСредстваНаличные.Остатки(, Касса.ОтображатьДС = ИСТИНА) КАК ДСОстатки
        |;
        |////////////////////////////////////////////////////////////////////////////////
        |ВЫБРАТЬ
        |   СтруктураПредприятия.Ссылка КАК Подразделение,
        |   ЕСТЬNULL(втВыручка.СуммаВыручкиОборот, 0) КАК СуммаВыручкиОборот,
        |   ЕСТЬNULL(втДС.СуммаОстаток, 0) КАК СуммаОстаток
        |ИЗ
        |   Справочник.СтруктураПредприятия КАК СтруктураПредприятия
        |   ЛЕВОЕ СОЕДИНЕНИЕ втВыручка КАК втВыручка
        |       ПО СтруктураПредприятия.Ссылка = втВыручка.Подразделение
        |   ЛЕВОЕ СОЕДИНЕНИЕ втДС КАК втДС
        |       ПО СтруктураПредприятия.Ссылка = втДС.Подразделение
        |ГДЕ
        |   (ЕСТЬNULL(втВыручка.СуммаВыручкиОборот, 0) > 0
        |       ИЛИ ЕСТЬNULL(втДС.СуммаОстаток, 0) > 0)";
    
    Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ТекущаяДатаСеанса()));
    Запрос.УстановитьПараметр("КонецПериода", КонецДня(ТекущаяДатаСеанса()));
    
    ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
    ЗначениеВРеквизитФормы(ТаблицаРезультата, "СводкаДанных");
    
КонецПроцедуры

Ограничения и рекомендации по работе с динамическими списками

Подведем итоги и перечислим важные правила при проектировании запросов динамических списков:

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