Как заменить источник в СхемеЗапроса 1С, сохранив отборы и поля

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

При работе со сложными динамическими запросами в 1С программисты часто сталкиваются с необходимостью программного изменения текста запроса. Объект СхемаЗапроса предоставляет мощные инструменты для объектного управления структурой SQL-подобного кода. Однако одна из самых частых и неочевидных задач — это замена одной таблицы на другую (например, одного вида документа на другой) без потери всех настроенных условий ГДЕ, выбранных полей и связей. Рассмотрим, почему стандартные методы удаления и добавления здесь не работают и как правильно реализовать замену через коллекцию доступных таблиц.

Проблема прямой модификации источников

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

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

Разберем по шагам правильный алгоритм, который позволит выполнить "бесшовную" подмену таблицы.

Алгоритм правильной замены источника

Для успешной замены нам понадобится доступ к коллекции ДоступныеТаблицы внутри пакета запроса. Именно оттуда нужно получать объект для замены. Рассмотрим программную реализацию этой задачи.


// Создаем или получаем существующую схему
СхемаЗапроса = Новый СхемаЗапроса;
СхемаЗапроса.УстановитьТекстЗапроса(ТекстВашегоЗапроса);

// Работаем с первым пакетом и первым оператором (типовой случай)
ПакетЗапроса = СхемаЗапроса.ПакетЗапросов[0];
ОператорЗапроса = ПакетЗапроса.Операторы[0];

// 1. Находим старый источник, который хотим заменить (например, самый первый)
ИсточникЗапроса = ОператорЗапроса.Источники[0];

// 2. Важный момент: сохраняем старый псевдоним!
// Именно по этому псевдониму схема сопоставляет поля и условия.
СтарыйПсевдоним = ИсточникЗапроса.Источник.Псевдоним;

// 3. Ищем новую таблицу в коллекции доступных таблиц пакета
// ИмяТаблицы должно быть в формате "Документ.РеализацияТоваровУслуг"
ИмяНовойТаблицы = "Документ.ЗаказПокупателя"; 
ТаблицаСхемыЗапроса = ПакетЗапроса.ДоступныеТаблицы.Найти(ИмяНовойТаблицы);

Если ТаблицаСхемыЗапроса = Неопределено Тогда
    ВызватьИсключение "Таблица " + ИмяНовойТаблицы + " не найдена в метаданных!";
КонецЕсли;

// 4. Выполняем замену
// Обратите внимание: передаем именно объект ТаблицаСхемыЗапроса
ОператорЗапроса.Источники.Заменить(0, ТаблицаСхемыЗапроса);

// 5. Восстанавливаем псевдоним для нового источника
// Теперь источник по индексу 0 — это наша новая таблица
ОператорЗапроса.Источники[0].Источник.Псевдоним = СтарыйПсевдоним;

// Получаем обновленный текст запроса
НовыйТекст = СхемаЗапроса.ПолучитьТекстЗапроса();

Почему это работает? Анализируем внутренние механизмы

Секрет успеха кроется в свойстве Псевдоним. В СхемеЗапроса все выбранные поля (ВыбираемыеПоля) и условия (Условия) хранят ссылки не на конкретную физическую таблицу, а на логический псевдоним источника в контексте данного оператора. Когда мы используем метод Заменить, 1С пытается сохранить структуру запроса. Если мы сразу после замены возвращаем источнику его старое имя (псевдоним), то выражения вида Псевдоним.ИмяПоля остаются валидными.

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

Сложные случаи: Объединения и Вложенные запросы

Проанализируем ситуацию, когда запрос состоит из множества блоков ОБЪЕДИНИТЬ. Если вам нужно заменить источник во всех 35 кусках (как упоминалось в обсуждении), не обязательно вручную перебирать каждый. Рассмотрим эффективный прием с использованием эталонного оператора.

Вы можете создать один "чистый" оператор, настроить его как шаблон, а затем добавлять его в коллекцию операторов. Выясним, как это сделать:


// Предположим, у нас есть настроенный ОператорЭталон
Для Каждого ИмяДокумента Из МассивИменДокументов Цикл
    // Добавляем новый оператор на основе эталона
    НовыйОператор = ПакетЗапроса.Операторы.Добавить(ОператорЭталон);
    
    // Теперь меняем в нем источник по уже известной схеме
    НоваяТаблица = ПакетЗапроса.ДоступныеТаблицы.Найти("Документ." + ИмяДокумента);
    НовыйОператор.Источники.Заменить(0, НоваяТаблица);
    
    // Псевдоним в новом операторе можно оставить общим для всех
    НовыйОператор.Источники[0].Источник.Pсевдоним = "ДокументРегистратор";
КонецЦикла;

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

Выводы и рекомендации

Мы рассмотрели основной способ программного управления источниками данных. Подведем итоги:

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

Объект СхемаЗапроса — это мощный инструмент, который при правильном подходе избавляет от ошибок ручного парсинга текста, гарантируя, что итоговый запрос будет синтаксически корректным с точки зрения платформы 1С.

← На главную