При разработке отчетов и механизмов выборки данных часто возникает задача динамического изменения структуры запроса в зависимости от условий или переданных параметров. Например, требуется изменить секцию ИТОГИ ПО, сгруппировать данные по разным полям или переключить сортировку.
Разберем основные ограничения платформы 1С:Предприятие при работе с запросами, а также рассмотрим все доступные практические способы решения этой задачи.
Прежде чем приступать к формированию условий, выясним важную особенность платформы: параметры запроса (передаваемые через метод УстановитьПараметр() и обозначаемые символом &) передаются в СУБД исключительно как константы или значения выражений.
Параметры нельзя использовать вместо структурных элементов запроса:
СГРУППИРОВАТЬ ПО, УПОРЯДОЧИТЬ ПО и ИТОГИ ПО.Поэтому простая передача имени поля через параметр внутри секции итогов вызовет синтаксическую ошибку. Для решения задачи требуется динамически менять сам текст запроса либо использовать специализированные объекты платформы.
Проанализируем базовый и наиболее распространенный метод — склеивание строк текста запроса в зависимости от логических условий в коде 1С.
Посмотрим на пример реализации:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| ЗаказПокупателя.Ссылка КАК Ссылка,
| ЗаказПокупателя.Номер КАК НомерЗаказ,
| ЗаказПокупателя.Дата КАК ДатаЗаказ,
| ЗаказПокупателя.СуммаДокумента КАК Сумма
|ИЗ
| Документ.ЗаказПокупателя КАК ЗаказПокупателя
|УПОРЯДОЧИТЬ ПО
| ДатаЗаказ";
Если ГруппироватьПоНомерам Тогда
Запрос.Текст = Запрос.Текст + "
|ИТОГИ
| СУММА(Сумма)
|ПО
| НомерЗаказ";
Иначе
Запрос.Текст = Запрос.Текст + "
|ИТОГИ
| СУММА(Сумма)
|ПО
| ДатаЗаказ";
КонецЕсли;
Результат = Запрос.Выполнить();
Рассмотрим подход, позволяющий сохранить целостность базового текста запроса для его удобного редактирования в Конструкторе запросов. В месте подстановки динамического фрагмента пишется уникальная строка-маркер, которая перед выполнением заменяется нужным текстом.
Посмотрим на пример с использованием функции СтрЗаменить:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Номер КАК НомерЗаказ,
| Заказ.Дата КАК ДатаЗаказ,
| Заказ.Сумма КАК Сумма
|ИЗ
| Документ.ЗаказПокупателя КАК Заказ
|ИТОГИ
| СУММА(Сумма)
|ПО
| #ПолеИтогов";
ПолеИтога = ?(ГруппироватьПоНомерам, "НомерЗаказ", "ДатаЗаказ");
Запрос.Текст = СтрЗаменить(Запрос.Текст, "#ПолеИтогов", ПолеИтога);
Результат = Запрос.Выполнить();
Также для форматирования строк удобно использовать системную функцию СтрШаблон(), которая повышает читаемость кода при подстановке нескольких фрагментов.
Разберем более строгий и объектный способ модификации запроса с помощью встроенного объекта СхемаЗапроса. Он позволяет разобрать текст запроса в иерархическую структуру объектов, программно управлять полями, группировками, условиями и итогами без риска допустить опечатку в синтаксисе.
Посмотрим на пример работы со схемой:
Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(БазовыйТекстЗапроса);
Выборка = Схема.ПакетЗапросов[0];
// Очищаем коллекцию итогов и добавляем нужное измерение
Выборка.КонтрольныеТочкиИтогов.Очистить();
Если ГруппироватьПоНомерам Тогда
Выборка.Итоги.Добавить("НомерЗаказ");
Иначе
Выборка.Итоги.Добавить("ДатаЗаказ");
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = Схема.ПолучитьТекстЗапроса();
Результат = Запрос.Выполнить();
Важное замечание: парсинг текста через СхемаЗапроса требует больше вычислительных ресурсов, чем строковые операции, поэтому данный объект не рекомендуется многократно создавать внутри высоконагруженных циклов.
Если задача заключается в формировании отчета с динамическими группировками, полями и итогами, оптимальным стандартом платформы 1С является использование Системы компоновки данных. Через КомпоновщикНастроек разработчик или пользователь может включать и отключать любые группировки, а платформа автоматически сформирует оптимальный SQL-запрос только с необходимыми соединениями и полями.