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