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

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

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

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

Способ 1. Динамическая сборка текста запроса (Конкатенация)

Этот метод является самым прямолинейным и часто используемым в простых обработках. Суть заключается в том, что мы формируем строку запроса, вставляя имя нужной колонки прямо в текст перед созданием объекта Запрос. Разберем этот подход на примере, предложенном в обсуждении.

Предположим, у нас есть параметр НомерКолонки, который принимает значение от 6 до 10. Нам нужно получить поля с 1 по 5 и одно дополнительное. Проанализируем программный код:


ЗначениеПараметра = "06"; // Это может быть получено из формы
ТекстЗапроса = 
"ВЫБРАТЬ
|   Таб.Поле01 КАК Поле01,
|   Таб.Поле02 КАК Поле02,
|   Таб.Поле03 КАК Поле03,
|   Таб.Поле04 КАК Поле04,
|   Таб.Поле05 КАК Поле05,
|   Таб.Поле" + ЗначениеПараметра + " КАК ДинамическоеПоле
|ИЗ
|   РегистрСведений.МоиДанные КАК Таб";

Запрос = Новый Запрос(ТекстЗапроса);
РезультатЗапроса = Запрос.Выполнить();

Важный нюанс: при использовании такого подхода Конструктор запроса не сможет открыть этот текст, так как он собирается "на лету" во время выполнения кода. Однако этот метод максимально производителен, так как сервер СУБД получает уже готовый, оптимизированный текст запроса.

Способ 2. Использование подстановочных маркеров (Метод СтрЗаменить)

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

Рассмотрим шаги реализации:

  1. В конструкторе запроса создаем поле с псевдонимом, например, &ПолеДляЗамены.
  2. Перед выполнением запроса используем функцию СтрЗаменить().

Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   Продажи.Номенклатура,
|   Продажи.Количество,
|   Продажи.ВЫБРАННОЕ_ПОЛЕ
|ИЗ
|   РегистрНакопления.Продажи КАК Продажи";

// Заменяем маркер на реальное имя колонки из метаданных или параметра
Запрос.Текст = СтрЗаменить(Запрос.Текст, "Продажи.ВЫБРАННОЕ_ПОЛЕ", "Продажи.СуммаОборот");

Результат = Запрос.Выполнить();

Такой метод позволяет визуально контролировать структуру запроса, оставляя динамической только одну его часть.

Способ 3. Использование конструкции ВЫБОР в самом запросе

Если количество возможных вариантов колонок невелико (например, те самые 12 месяцев), можно избежать динамической сборки текста и воспользоваться оператором ВЫБОР. В этом случае запрос остается статическим, а логика выбора переносится на сторону сервера базы данных.

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


Запрос = Новый Запрос;
Запрос.Текст = 
"ВЫБРАТЬ
|   Данные.Сотрудник,
|   ВЫБОР 
|       КОГДА &ИмяПоля = ""Поле1"" ТОГДА Данные.Поле1
|       КОГДА &ИмяПоля = ""Поле2"" ТОГДА Данные.Поле2
|       ИНАЧЕ Данные.ПолеПоУмолчанию
|   КОНЕЦ КАК РезультатПоля
|ИЗ
|   Справочник.Сотрудники КАК Данные";

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

Обратите внимание: типы данных во всех ветках конструкции ВЫБОР должны быть совместимы, иначе запрос может вернуть ошибку или неожиданный результат.

Способ 4. Постобработка в Таблице Значений

Иногда проще выбрать все возможные колонки, а затем удалить лишние из результирующей таблицы значений. Это удобно, если выгрузка данных происходит в интерфейсную таблицу на форме.

Проанализируем ситуацию: мы получаем все 10 колонок в запросе, а затем применяем метод Скопировать(). Этот метод работает крайне эффективно, так как он не просто удаляет столбцы, а создает новую структуру таблицы только с нужными данными.


// Получаем полную таблицу
ТЗ_Результат = Запрос.Выполнить().Выгрузить();

// Определяем список нужных колонок (5 обязательных + 1 динамическая)
НужныеКолонки = "Поле1, Поле2, Поле3, Поле4, Поле5, " + ВыбранноеПользователемИмя;

// Создаем новую таблицу только с выбранными данными
ФинальнаяТЗ = ТЗ_Результат.Скопировать(, НужныеКолонки);

Этот способ "чище" с точки зрения кода запроса, но требует передачи чуть большего объема данных от сервера к клиенту, если колонок изначально очень много.

Способ 5. Программная работа со Схемой Запроса

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

Разберем по шагам:

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

Схема = Новый СхемаЗапроса;
Схема.УстановитьТекст(ТекстБазовогоЗапроса);

Выборка = Схема.Пакеты[0].Операторы[0];
// Добавляем новое поле динамически
Выборка.ВыбранныеПоля.Добавить("Источник.Поле" + НомерПоля);

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

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

Резюме и рекомендации

Выбор конкретного метода зависит от архитектуры вашей задачи:

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

← На главную