Как подставить имя регистра в запрос 1С в зависимости от условия?

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

При разработке алгоритмов проведения или проверки остатков часто возникает необходимость обращаться к различным регистрам накопления в зависимости от реквизитов документа или справочника. Например, в зависимости от вида склада товары могут учитываться на регистрах ТоварыНаСкладах, ТоварыВРознице или ТоварыВНТТ.

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

Решение 1: Использование функции СтрЗаменить

Наиболее простое и распространенное решение — написать текст запроса с подстановочной маркой (меткой-заполнителем), после чего перед выполнением запроса заменить её на фактическое имя регистра с помощью функции встроенного языка СтрЗаменить.

Разберем по шагам, как правильно реализовать данный подход:

  1. В тексте запроса на месте имени регистра укажем метку, например НужныйРегистр.
  2. Определим требуемое имя регистра в зависимости от условия.
  3. Применим функцию СтрЗаменить к свойству Запрос.Текст.

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


// Определяем имя регистра
Если Ссылка.СкладОтправитель.ВидСклада = Перечисления.ВидыСкладов.НТТ Тогда
    ИмяРегистра = "ТоварыВНТТ";
ИначеЕсли Ссылка.СкладОтправитель.ВидСклада = Перечисления.ВидыСкладов.Розничный Тогда
    ИмяРегистра = "ТоварыВРознице";
Иначе
    ИмяРегистра = "ТоварыНаСкладах";
КонецЕсли;

// Формируем текст запроса с меткой
ТекстЗапроса = "ВЫБРАТЬ
|   РеализацияТоваровУслугТовары.НомерСтроки КАК НомерСтроки,
|   РеализацияТоваровУслугТовары.Номенклатура КАК Номенклатура,
|   РеализацияТоваровУслугТовары.ХарактеристикаНоменклатуры КАК ХарактеристикаНоменклатуры,
|   РеализацияТоваровУслугТовары.СерияНоменклатуры КАК СерияНоменклатуры,
|   СУММА(РеализацияТоваровУслугТовары.Количество) КАК КоличествоНужно,
|   СУММА(ЕСТЬNULL(ТоварыОстатки.КоличествоОстаток, 0)) КАК КоличествоОстаток
|ИЗ
|   Документ.РеализацияТоваровУслуг.Товары КАК РеализацияТоваровУслугТовары
|   ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.НужныйРегистр.Остатки(&ВремяДока, Склад = &Склад) КАК ТоварыОстатки
|   ПО РеализацияТоваровУслугТовары.Номенклатура = ТоварыОстатки.Номенклатура
|   И РеализацияТоваровУслугТовары.ХарактеристикаНоменклатуры = ТоварыОстатки.ХарактеристикаНоменклатуры
|   И РеализацияТоваровУслугТовары.СерияНоменклатуры = ТоварыОстатки.СерияНоменклатуры
|ГДЕ
|   РеализацияТоваровУслугТовары.Ссылка = &Ссылка
|СГРУППИРОВАТЬ ПО
|   РеализацияТоваровУслугТовары.НомерСтроки,
|   РеализацияТоваровУслугТовары.Номенклатура,
|   РеализацияТоваровУслугТовары.ХарактеристикаНоменклатуры,
|   РеализацияТоваровУслугТовары.СерияНоменклатуры";

// Подставляем реальное имя регистра
Запрос = Новый Запрос;
Запрос.Текст = СтрЗаменить(ТекстЗапроса, "НужныйРегистр", ИмяРегистра);

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

Решение 2: Использование объекта СхемаЗапроса

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

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

Решение 3: Статический запрос с ОБЪЕДИНИТЬ ВСЕ

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

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

Важные рекомендации по оптимизации запроса

Проанализируем исходный запрос и выделим несколько критических моментов, которые влияют на производительность и корректность получаемых данных:

  1. Передача отбора в параметры виртуальной таблицы: Указание условия Склад = &Склад в параметрах виртуальной таблицы остатков обязательно. Однако если передавать только склад, система прочитает остатки по всем позициям данного склада. Чтобы ускорить выборку, передавайте в параметры виртуальной таблицы список номенклатуры документа с помощью отбора: Номенклатура В (&МассивНоменклатуры) или через временную таблицу.
  2. Избавление от разнумерования строк и группировок: Группировка по полю НомерСтроки при левом соединении с остатками может привести к задвоению данных или некорректному списанию, если одинаковая номенклатура встречается в нескольких строках документа. Правильнее сначала поместить свернутую табличную часть документа во временную таблицу, а затем соединять её с виртуальной таблицей остатков.
  3. Избегайте неявных соединений (вызовов через точку): Вызовы вида Номенклатура.ЕдиницаХраненияОстатков.Коэффициент и Ссылка.СкладОтправитель создают скрытые левые соединения к реквизитам на уровне СУБД. Значения реквизитов шапки рекомендуется передавать отдельными параметрами запроса.
  4. Передача момента времени: В качестве параметра даты для расчета остатков &ВремяДока при проведении документа необходимо передавать объект МоментВремени или Граница, чтобы остатки рассчитывались корректно с учетом позиции документа на оси времени.
← На главную