Как связать два набора данных в СКД по условию ИЛИ?

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

При разработке отчетов в системе компоновки данных (СКД) разработчики часто сталкиваются с задачей соединения двух наборов данных по сложному условию вида Лево.ПолеА = Право.ПолеА ИЛИ Лево.ПолеБ = Право.ПолеБ. Разберем особенности работы платформы 1С:Предприятие при связывании наборов и проанализируем возможные варианты реализации такого сопоставления.

Ограничения стандартного механизма связей наборов данных

Проанализируем, как работает вкладка Связи наборов данных в схеме компоновки:

  1. Строгое объединение по «И»: Если добавить несколько строк связей между одним источником и приемником, СКД всегда объединяет их логическим оператором И (конъюнкция). Возможность переключить логику на ИЛИ в интерфейсе отсутствует.
  2. Назначение колонки «Условие связи»: Выражение в этой колонке предназначено исключительно для фильтрации строк набора-источника перед выполнением соединения и не позволяет проверять поля набора-приемника.
  3. Ограничение для наборов типа «Объект»: Механизм передачи параметров из источника в приемник работает только тогда, когда второй набор данных является запросом. Если в качестве приемника используется НаборДанных-Объект (например, переданная из кода ТаблицаЗначений), сопоставление выполняется компоновщиком исключительно в оперативной памяти по точным совпадениям ключевых полей.

Рассмотрим практические способы обхода данных ограничений в зависимости от структуры наборов данных.

Способ 1. Передача параметров в подчиненный набор данных-запрос

Если второй набор данных представляет собой НаборДанных-Запрос, можно передавать поля из ведущего набора как параметры в текст запроса ведомого набора. Разберем по шагам, как настроить такую схему:

  1. В тексте запроса второго набора данных задаем условие с использованием параметров:
    
    ВЫБРАТЬ
        ТаблицаПриемник.ПолеА КАК ПолеА,
        ТаблицаПриемник.ПолеБ КАК ПолеБ,
        ТаблицаПриемник.Значение КАК Значение
    ИЗ
        РегистрСведений.Данные КАК ТаблицаПриемник
    ГДЕ
        (ТаблицаПриемник.ПолеА = &ПараметрА ИЛИ ТаблицаПриемник.ПолеБ = &ПараметрБ)
    
  2. Переходим на вкладку Связи наборов данных и создаем две связи:
    • Первая связь: Источник — НаборДанных1, Приемник — НаборДанных2, Условие связи оставляем пустым, в колонке Параметры указываем имя параметра ПараметрА, а в выражении источника — поле ПолеА.
    • Вторая связь: аналогично передаем поле ПолеБ в параметр ПараметрБ.

В этом случае платформа для каждой строки первого набора данных будет вызывать второй запрос, передавая текущие значения строк в параметры &ПараметрА и &ПараметрБ, и отбирать записи по условию ИЛИ.

Способ 2. Использование Менеджера временных таблиц вместо набора-объекта

Если один из наборов данных формируется программно в виде таблицы значений, наиболее производительным и надежным решением является отказ от НабораДанных-Объект в пользу одного НабораДанных-Запрос с использованием МенеджераВременныхТаблиц.

Разберем пример реализации в коде перед формированием отчета:


// Создаем менеджер временных таблиц
МенеджерВТ = Новый МенеджерВременныхТаблиц;

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

// Передаем менеджер временных таблиц в настройки компоновщика
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиОтчета, ДанныеРасшифровки);

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);

// В основном запросе схемы связываем таблицы напрямую

В тексте запроса схемы компоновки данных выполняем стандартное соединение с созданной временной таблицей:


ВЫБРАТЬ
    ОсновнаяТаблица.Ссылка КАК Ссылка,
    ВТ_ВнешниеДанные.Данные КАК Данные
ИЗ
    Документ.БольничныйЛист КАК ОсновнаяТаблица
    ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ВнешниеДанные КАК ВТ_ВнешниеДанные
        ПО (ОсновнаяТаблица.ПервичныйБольничныйЛист = ВТ_ВнешниеДанные.ПолеА 
            ИЛИ ОсновнаяТаблица.ИсправленныйДокумент = ВТ_ВнешниеДанные.ПолеБ)

Способ 3. Трансформация строк таблицы значений (размножение ключей)

Если необходимо сохранить структуру именно с НаборомДанных-Объект, можно подготовить данные таблицы значений до передачи в СКД, размножив строки по каждому условию связи:

  1. В коде формирования таблицы значений добавляем единую колонку КлючСвязи.
  2. Для каждой исходной строки создаем дубликаты: в первой копии помещаем в КлючСвязи значение из ПолеА, во второй — значение из ПолеБ.
  3. На вкладке Связи наборов данных настраиваем стандартное равенство: НаборДанных1.Ключ = НаборДанных2.КлючСвязи.
  4. Чтобы избежать задвоения числовых показателей в отчете, для ресурсов используем агрегатные функции МАКСИМУМ() или группировку с устранением дублей.

Способ 4. Фильтрация через вычисляемое поле

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

  1. На вкладке Вычисляемые поля добавляем поле СоответствуетУсловию с выражением: Лево_ПолеА = Право_ПолеА ИЛИ Лево_ПолеБ = Право_ПолеБ
  2. В настройках отбора отчета устанавливаем условие: СоответствуетУсловию Равно Истина.

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

← На главную