Как в СКД выбирать данные из разных таблиц в зависимости от условия?

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

При разработке сложных отчетов на системе компоновки данных (СКД) часто возникает задача: в зависимости от значения параметра (например, выбор организации, типа учета или переключателя «План/Факт») получать данные из разных источников — разных регистров или разных временных таблиц. Рассмотрим, как реализовать это максимально эффективно, избежав лишней нагрузки на сервер базы данных.

Проблема использования ПОЛНОГО СОЕДИНЕНИЯ

Типичная ошибка начинающего разработчика — попытка объединить две временные таблицы через ПОЛНОЕ СОЕДИНЕНИЕ (FULL JOIN) и затем выбирать поля через конструкцию ВЫБОР КОГДА. Рассмотрим, почему это неудачный подход:

Проанализируем правильные способы решения этой задачи.

Способ 1: Использование ОБЪЕДИНИТЬ ВСЕ с фильтрацией

Самый простой и эффективный способ внутри одного запроса — это использование оператора ОБЪЕДИНИТЬ ВСЕ (UNION ALL). Вместо того чтобы соединять таблицы «в ширину», мы соединяем их «в длину», отсекая ненужные данные на уровне условий.

Разберем пример реализации. Допустим, у нас есть две временные таблицы ВТ_Регистр1 и ВТ_Регистр2. Нам нужно выбрать данные из одной из них в зависимости от параметра &Параметр.


ВЫБРАТЬ
    ВТ_Регистр1.Номенклатура КАК Номенклатура,
    ВТ_Регистр1.Количество КАК Количество
ИЗ
    ВТ_Регистр1 КАК ВТ_Регистр1
ГДЕ
    &Параметр = 1

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ВТ_Регистр2.Номенклатура,
    ВТ_Регистр2.Количество
ИЗ
    ВТ_Регистр2 КАК ВТ_Регистр2
ГДЕ
    &Параметр = 2

Важный нюанс: Многие разработчики по привычке пишут условия через ВЫБОР КОГДА &Параметр = 1 ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ. Однако платформа 1С позволяет использовать простое сравнение параметра в секции ГДЕ. Это делает код чище и понятнее. Оптимизатор запросов СУБД в большинстве случаев поймет, что одно из условий всегда ложно, и не будет выполнять «пустую» часть запроса.

Способ 2: Программное управление наборами данных

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

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

  1. Создадим в схеме СКД два разных набора данных (запроса).
  2. В обработчике ПриКомпоновкеРезультата проанализируем значение параметра.
  3. Установим свойство Использование для того набора данных, который не нужен.

Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь; // Берем управление в свои руки
    
    // Получаем значение параметра из настроек компоновщика
    ЗначениеПараметра = КомпоновщикНастроек.Настройки.ПараметрыДанных.Элементы.Найти("ТипИсточника").Значение;
    
    Если ЗначениеПараметра = 1 Тогда
        // Отключаем второй набор данных
        СхемаКомпоновкиДанных.НаборыДанных.НаборДанныхРегистр2.Использование = Ложь;
    Иначе
        // Отключаем первый набор данных
        СхемаКомпоновкиДанных.НаборыДанных.НаборДанныхРегистр1.Использование = Ложь;
    КонецЕсли;
    
    // Выполняем стандартную компоновку с измененной схемой
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, КомпоновщикНастроек.Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Этот метод гарантирует, что 1С не будет даже пытаться подготовить или выполнить запрос к отключенной таблице.

Способ 3: Динамическая подмена текста запроса

Иногда источники данных настолько разные, что проще всего программно изменить сам текст запроса перед его выполнением. Мы можем использовать в тексте запроса строковый маркер (например, //ИМЯ_ТАБЛИЦЫ) и заменять его на нужное имя метаданных.

Рассмотрим пример изменения свойства Запрос у набора данных:


ТекстЗапроса = СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Запрос;
Если &Параметр = 1 Тогда
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", "РегистрНакопления.Продажи");
Иначе
    ТекстЗапроса = СтрЗаменить(ТекстЗапроса, "&ИмяТаблицы", "РегистрНакопления.Закупки");
КонецЕсли;
СхемаКомпоновкиДанных.НаборыДанных.НаборДанных1.Запрос = ТекстЗапроса;

Важно: При таком подходе нужно следить, чтобы состав полей (псевдонимы) в обоих вариантах запроса совпадал, иначе СКД выдаст ошибку при попытке обращения к несуществующим полям.

Дополнительные рекомендации

При выборе метода ориентируйтесь на следующие критерии:

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

← На главную