Как правильно заменить или добавить фрагмент в текст запроса с помощью СтрЗаменить в 1С

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

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

Причина 1: СтрЗаменить — это функция, а не процедура

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

Посмотрим на ошибочный вариант вызова:


// Ошибка: результат функции никуда не записывается
Если ЭтотОбъект.Условие Тогда
    СтрЗаменить(ТекстЗапроса, "СтрокаПоиска", "СтрокаЗамены");
КонецЕсли;

Правильная конструкция требует явного присваивания возвращаемого значения переменной:


// Корректное присваивание результата
Если ЭтотОбъект.Условие Тогда
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "СтрокаПоиска", "СтрокаЗамены");
КонецЕсли;

Причина 2: Точное совпадение подстроки поиска

Функция СтрЗаменить чувствительна к регистру символов, неразрывным пробелам, символам табуляции и переводам строк. Если в тексте запроса ключевые слова написаны строчными буквами, а в строке поиска — прописными (или наоборот), замена не выполнится. Также важно следить за совпадением пробелов между словами.

Способ 1. Корректная замена многострочного блока в тексте запроса

Разберем, как добавить блок ОБЪЕДИНИТЬ ВСЕ с новым периодом к уже существующему тексту запроса. Для переноса строк во встроенном языке 1С используется символ вертикальной черты | внутри строкового литерала. При этом для интерпретатора запросов количество пробелов и знаков переноса строк не имеет значения — запрос воспринимается корректно, даже если написан в одну строку.

Рассмотрим пример кода:


ТекстЗапроса = Запрос.Текст;

СтрокаПоиска = "Датавремя(2017,12,31) как конпериода";

СтрокаЗамены = "Датавремя(2017,12,31) как конпериода
|ОБЪЕДИНИТЬ ВСЕ
|ВЫБРАТЬ
|    ДАТАВРЕМЯ(2018, 01, 01) КАК Период,
|    ДАТАВРЕМЯ(2018, 12, 31) КАК КонПериода";

Если ЭтотОбъект.Условие Тогда
    Запрос.Текст = СтрЗаменить(ТекстЗапроса, СтрокаПоиска, СтрокаЗамены);
КонецЕсли;

Способ 2. Использование явных маркеров-заполнителей

Поиск по смысловым фрагментам запроса (например, по конкретным именам полей или датам) несет риск: если в коде изменится хотя бы один символ, замена перестанет работать. Чтобы избежать этого, в текст запроса заранее помещают комментарии-метки, по которым затем производят подстановку.

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

  1. В текст запроса помещаем уникальную метку в виде комментария, например //&ДополнительныйПериод.
  2. В кодовой части выполняем замену метки на нужный блок или на пустую строку.

ТекстЗапроса = 
"ВЫБРАТЬ
|    ДАТАВРЕМЯ(2017, 01, 01) КАК Период,
|    ДАТАВРЕМЯ(2017, 12, 31) КАК КонПериода
|ПОМЕСТИТЬ ВТ_пер
|//&ДополнительныйПериод
|;";

Если ЭтотОбъект.Условие Тогда
    ТекстВставки = 
    "ОБЪЕДИНИТЬ ВСЕ
    |ВЫБРАТЬ
    |    ДАТАВРЕМЯ(2018, 01, 01) КАК Период,
    |    ДАТАВРЕМЯ(2018, 12, 31) КАК КонПериода";
    
    Запрос.Текст = СтрЗаменить(ТекстЗапроса, "//&ДополнительныйПериод", ТекстВставки);
Иначе
    Запрос.Текст = СтрЗаменить(ТекстЗапроса, "//&ДополнительныйПериод", "");
КонецЕсли;

Способ 3. Передача периодов через Таблицу Значений в качестве параметра

Самым надежным и гибким решением задачи формирования списка периодов является отказ от динамической сборки текста через ОБЪЕДИНИТЬ ВСЕ в пользу передачи объекта ТаблицаЗначений во временную таблицу запроса.

Разберем по шагам, как это устроено:

  1. Создаем объект ТаблицаЗначений и добавляем типизированные колонки с датами.
  2. Заполняем таблицу нужными периодами в цикле.
  3. Передаем таблицу в параметр запроса методом УстановитьПараметр.
  4. В запросе помещаем параметр во временную таблицу с помощью конструкции ВЫБРАТЬ ... ПОМЕСТИТЬ ВТ_пер ИЗ &ТаблицаПериодов.

Рассмотрим пример кода:


// 1. Формируем таблицу периодов
ТаблицаПериодов = Новый ТаблицаЗначений;
ТаблицаПериодов.Колонки.Добавить("Период", Новый ОписаниеТипов("Дата"));
ТаблицаПериодов.Колонки.Добавить("КонПериода", Новый ОписаниеТипов("Дата"));

ГодНачала = 2010;
ГодОкончания = ?(ЭтотОбъект.Условие, 2018, 2017);

Для Год = ГодНачала По ГодОкончания Цикл
    НоваяСтрока = ТаблицаПериодов.Добавить();
    НоваяСтрока.Период = Дата(Год, 1, 1);
    НоваяСтрока.КонПериода = Дата(Год, 12, 31, 23, 59, 59);
КонецЦикла;

// 2. Инициализируем запрос и передаем параметр
Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|    ТЗ.Период КАК Период,
|    ТЗ.КонПериода КАК КонПериода
|ПОМЕСТИТЬ ВТ_пер
|ИЗ
|    &ТаблицаПериодов КАК ТЗ
|;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ
|    ВТ_пер.Период,
|    ВТ_пер.КонПериода
|ИЗ
|    ВТ_пер КАК ВТ_пер";

Запрос.УстановитьПараметр("ТаблицаПериодов", ТаблицаПериодов);
Результат = Запрос.Выполнить();

Способ 4. Программное изменение через объект СхемаЗапроса

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

← На главную