Как программно добавить поле во временную таблицу и последующие выборки через Схему запроса

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

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

Выясним причину возникновения ошибки

Проанализируем ситуацию: когда мы загружаем текст запроса в СхемаЗапроса, объект строит внутреннее дерево метаданных этого запроса. Если в запросе используется временная таблица (например, Т), схема жестко фиксирует список ее полей на основе того фрагмента запроса, где эта таблица была создана (команда ПОМЕСТИТЬ).

Если мы попытаемся добавить поле в оператор ВЫБРАТЬ, обращаясь к этой таблице (например, Т.НовыйРеквизит), система выполнит проверку соответствия. Поскольку в описании источника Т такого поля изначально не было, СхемаЗапроса выдаст исключение. Рассмотрим типичный ошибочный код:


ТекстЗапроса =
    "ВЫБРАТЬ
    |    Т.Номенклатура КАК Номенклатура
    |ИЗ
    |    Т КАК Т";
    
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);

// Попытка добавить поле напрямую приведет к ошибке "Поле не найдено"
ОсновнаяВыборка = СхемаЗапроса.ПакетЗапросов[0].Операторы[0];
ОсновнаяВыборка.ВыбираемыеПоля.Добавить("Т.ТипНоменклатуры"); 

Чтобы избежать этой ошибки, нам нужно действовать последовательно: сначала объявить поле в источнике данных, а уже затем добавлять его в список выбора.

Решение проблемы: регистрация поля в ДоступныеПоля

Разберем основной механизм решения. У каждого источника данных в схеме запроса есть коллекция ДоступныеПоля. Это своего рода «декларация» того, что мы можем получить из конкретной таблицы. Если мы работаем с временной таблицей, которая пришла «извне» или была сформирована ранее, нам нужно принудительно расширить этот список.

Рассмотрим пошаговый алгоритм:

  1. Получаем нужный пакет запроса из коллекции ПакетЗапросов.
  2. Обращаемся к конкретному оператору (обычно это первый и единственный оператор ВЫБРАТЬ в пакете).
  3. Находим нужный источник в коллекции Источники.
  4. Добавляем описание нового поля в ДоступныеПоля этого источника.
  5. И только после этого добавляем поле в ВыбираемыеПоля оператора.

Вот как выглядит исправленный код:


// 1. Инициализация схемы
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(ТекстЗапроса);

// 2. Получаем доступ к оператору выбора
ОператорВыбора = СхемаЗапроса.ПакетЗапросов[0].Операторы[0];

// 3. Добавляем поле в доступные поля источника (например, первого источника в запросе)
// Это "легализует" использование поля в дальнейшем
ОператорВыбора.Источники[0].Источник.ДоступныеПоля.Добавить("ТипНоменклатуры");

// 4. Теперь добавляем поле в список выбора без ошибок
ОператорВыбора.ВыбираемыеПоля.Добавить("Т.ТипНоменклатуры");

ТекстРезультата = СхемаЗапроса.ПолучитьТекстЗапроса();

Как «протащить» поле через всю цепочку временных таблиц

В реальных задачах запрос часто состоит из нескольких пакетов, где данные последовательно перекладываются из одной временной таблицы в другую. Если нам нужно добавить поле Артикул в финальную выборку, а оно появляется только в самом первом пакете, нам придется модифицировать каждый этап.

Проанализируем комплексный подход к решению этой задачи:

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

Особенности работы с ОБЪЕДИНИТЬ ВСЕ

Если ваш запрос содержит объединения (несколько операторов ВЫБРАТЬ, соединенных ключевым словом ОБЪЕДИНИТЬ), необходимо соблюдать строгое правило: количество и порядок полей во всех частях объединения должны совпадать.

Рассмотрим, как это реализовать программно. Пройдем циклом по всем операторам коллекции:


Для Каждого ТекущийОператор Из СхемаЗапроса.ПакетЗапросов[ИндексПакета].Операторы Цикл
    // Добавляем поле в каждый блок ОБЪЕДИНИТЬ
    ТекущийОператор.ВыбираемыеПоля.Добавить("Т.НовоеПоле");
КонецЦикла;

Дополнительные рекомендации и ограничения

При использовании СхемаЗапроса следует учитывать несколько технических нюансов, которые помогут сделать код более надежным:

1. Поиск источника по имени. Не всегда нужная таблица находится под индексом 0. Безопаснее искать источник по псевдониму или имени таблицы. Для этого можно перебирать коллекцию Источники и проверять свойство Источник.ИсточникДанных.

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

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

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

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

← На главную