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