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

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

При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются с особенностью механизма Связи наборов данных. По умолчанию СКД выполняет соединение между источником и приемником по принципу Left Join (левое внешнее соединение). Это означает, что если в наборе-источнике отсутствует какая-либо комбинация измерений (например, определенный склад или номенклатура), то данные из набора-приемника по этим измерениям просто не попадут в итоговый отчет. В этой статье мы подробно разберем, как обойти это ограничение и добиться эффекта Полного соединения (Full Join) в СКД.

Почему стандартные связи СКД работают как левое соединение?

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

Рассмотрим основной и самый эффективный способ решения этой задачи, который рекомендуют опытные разработчики.

Решение 1: Использование «Набора данных — объединение»

Вместо того чтобы связывать наборы данных (запросы) между собой через вкладку связей, мы воспользуемся механизмом объединения на уровне самой структуры наборов. Это позволит нам собрать данные из всех источников в единый поток, сохраняя при этом все записи из каждого набора.

Разберем по шагам:

  1. В схеме компоновки данных добавим новый Набор данных - объединение.
  2. Перетащим в него все наши существующие наборы данных (например, Запрос1, Запрос2, Запрос3).
  3. В каждом из вложенных запросов нам необходимо обеспечить идентичность имен полей, по которым будет происходить агрегация (Организация, Склад, Номенклатура, Сумма и т.д.).

Однако простое объединение может «смешать» данные разных отчетов, если они должны выводиться отдельно. Чтобы этого избежать, применим метод поля-дискриминатора.

Решение 2: Разделение данных через поле-идентификатор

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

Пример для Запрос1:


ВЫБРАТЬ
    "Продажи" КАК ИмяОтчета,
    Организация,
    Склад,
    СуммаПродажи КАК Сумма
ИЗ
    РегистрНакопления.Продажи

Пример для Запрос2:


ВЫБРАТЬ
    "Остатки" КАК ИмяОтчета,
    Организация,
    Склад,
    СуммаОстаток КАК Сумма
ИЗ
    РегистрНакопления.ТоварыНаСкладах.Остатки

Теперь в настройках СКД мы можем сгруппировать данные по полю ИмяОтчета. Это позволит нам вывести информацию в виде отдельных таблиц в одном отчете, а общие ресурсы будут суммироваться корректно по всем наборам, так как они находятся в одном родительском объединении.

Решение 3: Борьба с «исчезающими» данными при отборах

Рассмотрим проблему, когда пользователь устанавливает отбор по полю, которое присутствует только в одном из наборов (например, ВидОплаты). Если мы просто наложим отбор на весь отчет, то записи из наборов, где этого поля нет, примут значение NULL и будут отсечены фильтром. В итоге отчет может выйти пустым.

Чтобы избежать этой проблемы, выполним следующие действия:

  1. Выравнивание полей: В каждом запросе объединения добавим недостающие поля с пустыми значениями. Если в Запрос2 нет поля ВидОплаты, добавим его принудительно:
    
    ВЫБРАТЬ
        ...,
        ЗНАЧЕНИЕ(Справочник.ВидыОплаты.ПустаяСсылка) КАК ВидОплаты
    ИЗ
        ...
    
  2. Настройка условий в запросе: Если поле специфично только для одного набора, лучше передавать отбор через Параметры запроса. Это позволит отфильтровать данные одного источника, не затрагивая полноту данных других источников в объединении.

Решение 4: Метод «Эталонного набора данных»

Если по каким-то причинам использование «Набора данных — объединение» невозможно (например, сложная иерархия связей), можно применить метод Master Dataset. Мы создаем вспомогательный набор данных, который будет содержать все уникальные комбинации ключей из всех таблиц.

Рассмотрим структуру такого запроса:


ВЫБРАТЬ РАЗЛИЧНЫЕ Организация, Склад, Номенклатура ИЗ (
    ВЫБРАТЬ Организация, Склад, Номенклатура ИЗ Регистр1
    ОБЪЕДИНИТЬ
    ВЫБРАТЬ Организация, Склад, Номенклатура ИЗ Регистр2
    ОБЪЕДИНИТЬ
    ВЫБРАТЬ Организация, Склад, Номенклатура ИЗ Регистр3
) КАК ВсеКлючи

Затем в окне связей мы назначаем этот набор Источником, а все остальные — Приемниками. Поскольку в источнике теперь гарантированно есть все возможные комбинации измерений, левое соединение от него ко всем остальным наборам фактически превращается в полное соединение.

Нюансы использования функции ВычислитьВыражение

Выясним, как считать общие итоги, если данные все же остались в разных наборах. В СКД существует мощный инструмент — функция ВычислитьВыражение. Она позволяет обращаться к данным других группировок или даже других наборов данных.

Например, чтобы получить сумму из другого набора в контексте текущей группировки, можно использовать конструкцию:

Сумма(ВычислитьВыражение("Сумма", , , "Первая", "Последняя", "НазваниеВторогоНабора"))

Это бывает полезно для вывода сравнительных показателей в одной строке, когда прямое объединение запросов затруднено из-за разной детальности данных.

Важные замечания по производительности

Проанализируем нагрузку на систему. Использование связей наборов данных в СКД — это всегда серия запросов к СУБД. Если данных много (десятки тысяч строк в источнике), отчет может работать медленно. Набор данных — объединение обычно работает быстрее, так как компоновщик оптимизирует построение итогового запроса.

Подведем итог: Для имитации полного соединения в СКД наиболее правильным и современным подходом является использование Набора данных - объединение с предварительным «выравниванием» состава полей во всех вложенных запросах. Это гарантирует сохранение всех данных, корректную работу агрегатных функций (Сумма, Количество) и предсказуемое поведение пользовательских отборов.

← На главную