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