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

Программист 1С v8.3 (Управляемые формы)
← К списку

Мы с вами сталкиваемся с достаточно распространенной задачей в разработке отчетов на Системе Компоновки Данных (СКД) в 1С: как эффективно объединить или вывести информацию, полученную из нескольких независимых источников или наборов данных. Нередко возникает ситуация, когда эти наборы имеют разное количество строк, различную структуру или их объединение стандартными средствами СКД приводит к нежелательному перемножению данных. Давайте вместе разберемся в доступных подходах и выберем наиболее подходящее решение для вашей конкретной ситуации.

Объединение наборов данных (аналог UNION ALL)

Первый и самый очевидный способ, который предоставляет СКД для работы с несколькими наборами данных, это их объединение. Этот механизм аналогичен оператору UNION ALL в SQL-запросах и предназначен для вывода всех записей из каждого набора данных в единую структуру.

Как это работает?

  1. Мы создаем в схеме компоновки данных несколько наборов данных (например, типа "Запрос").
  2. Затем мы добавляем новый набор данных типа "Объединение".
  3. В настройках этого набора "Объединение" мы указываем, какие из ранее созданных наборов данных мы хотим объединить.

Требования и особенности

Для корректного использования этого метода важно соблюдать несколько условий:

Когда применять?

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

Рассмотрим пример, когда нам нужно объединить данные о продажах и возвратах:


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

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

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

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

Соединение наборов данных (аналог JOIN)

Второй мощный инструмент СКД — это соединение наборов данных. Этот подход позволяет связать несколько наборов данных между собой по аналогии с оператором JOIN в SQL-запросах.

Как это работает?

  1. Создаем несколько наборов данных в схеме СКД.
  2. Переходим на закладку "Связи наборов данных".
  3. Здесь мы определяем условия связи между полями разных наборов данных.

Особенности и применения

Связи наборов данных обычно реализуются как левое внешнее соединение. Это означает, что все записи из родительского (левого) набора данных будут отображены, а из зависимого (правого) набора — только те, которые соответствуют заданному условию связи. Если соответствия не найдено, поля из правого набора будут пустыми (NULL).

Соединение наборов данных удобно использовать в следующих случаях:

Нюансы с расчетом итогов

При соединении наборов данных могут возникать особенности в расчете итогов ресурсов, которые отличаются от соединения таблиц на уровне запроса. Например, если в одном наборе данных есть несколько строк, соответствующих одной строке другого набора, ресурсы могут задваиваться. Для обхода этих особенностей может потребоваться использование функции языка выражений СКД ВычислитьВыражениеСГруппировкойМассив. Эта функция позволяет агрегировать значения по определенным группировкам до того, как они будут соединены, или после соединения, но с учетом уникальных значений.

Для уменьшения количества строк во втором наборе данных при соединении, что может быть полезно для производительности, мы можем использовать отбор по параметру в запросе дочернего набора.

Программное формирование отчета с использованием набора данных "Объект"

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

Когда это необходимо?

Мы прибегаем к этому подходу, если:

Как это работает?

При использовании набора данных типа "Объект" мы:

  1. Определяем структуру набора данных (колонки и их типы) вручную в схеме СКД.
  2. Передаем данные в этот набор программно. Обычно это делается в процедуре ПриКомпоновкеРезультата модуля отчета. Мы можем заполнить таблицу значений в коде 1С и передать ее в набор данных "Объект".

Рассмотрим пример концептуального кода для заполнения набора данных "Объект":


// В модуле отчета, в процедуре ПриКомпоновкеРезультата

Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
    // Отключаем стандартную обработку, так как мы будем выводить результат программно
    СтандартнаяОбработка = Ложь;

    // Создаем таблицу значений, которая будет источником данных
    Перем ТаблицаДанных;
    ТаблицаДанных = Новый ТаблицаЗначений;
    ТаблицаДанных.Колонки.Добавить("Поле1", Новый ОписаниеТипов("Строка"));
    ТаблицаДанных.Колонки.Добавить("Поле2", Новый ОписаниеТипов("Число"));

    // Заполняем таблицу значений данными
    НоваяСтрока = ТаблицаДанных.Добавить();
    НоваяСтрока.Поле1 = "Значение 1";
    НоваяСтрока.Поле2 = 100;

    НоваяСтрока = ТаблицаДанных.Добавить();
    НоваяСтрока.Поле1 = "Значение 2";
    НоваяСтрока.Поле2 = 200;

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

    // Устанавливаем нашу таблицу значений в качестве источника для набора данных "Объект"
    // Предполагается, что в СКД есть набор данных с именем "НаборОбъект"
    ПроцессорКомпоновки.УстановитьДанныеНабораДанных("НаборОбъект", ТаблицаДанных);

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

    // Пример программного вывода (концептуально)
    Макет = ПолучитьМакет("МакетОтчета"); // Получаем собственный макет
    ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
    ОбластьЗаголовок.Параметры.ТекстЗаголовка = "Мой Программный Отчет";
    ДокументРезультат.Вывести(ОбластьЗаголовок);

    ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
    ДокументРезультат.Вывести(ОбластьШапкаТаблицы);

    Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
        ОбластьСтрока = Макет.ПолучитьОбласть("СтрокаТаблицы");
        ОбластьСтрока.Параметры.Поле1 = СтрокаТЗ.Поле1;
        ОбластьСтрока.Параметры.Поле2 = СтрокаТЗ.Поле2;
        ДокументРезультат.Вывести(ОбластьСтрока);
    КонецЦикла;

КонецПроцедуры

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

Сложные сценарии и обходы

Иногда задача не сводится к простому объединению или соединению. Что, если нам нужно вывести две совершенно независимые таблицы с разным количеством строк, объединенные одним логическим полем, но без перемножения строк? Например, нам нужен отчет, где в одной части выводятся данные о продажах, а в другой — о закупках, и эти части не должны влиять друг на друга в плане количества строк, но должны быть представлены в одном документе.

СКД для получения данных, но не для вывода

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

Использование параметров для выбора набора данных

Если задача состоит в том, чтобы по условию выводить данные из одной или другой таблицы (но не одновременно), мы можем использовать параметры отчета типа "Булево". В зависимости от значения такого параметра, мы можем либо активировать определенный набор данных, либо использовать условные выражения в запросах для выбора нужных полей.

Например, в запросе мы можем использовать конструкцию ВЫБОР КОГДА:


ВЫБРАТЬ
    ВЫБОР КОГДА &ИспользоватьПродажи ТОГДА Продажи.Номенклатура ИНАЧЕ Возвраты.Номенклатура КОНЕЦ КАК Номенклатура,
    ВЫБОР КОГДА &ИспользоватьПродажи ТОГДА Продажи.Количество ИНАЧЕ Возвраты.Количество КОНЕЦ КАК Количество
ИЗ
    (ВЫБРАТЬ Номенклатура, Количество ИЗ Документ.РеализацияТоваровУслуг.Товары) КАК Продажи,
    (ВЫБРАТЬ Номенклатура, Количество ИЗ Документ.ВозвратТоваровОтПокупателя.Товары) КАК Возвраты
ГДЕ
    // Здесь условие, которое связывает Продажи и Возвраты, если нужно их сопоставить
    // Или просто выбираем один из наборов, если они независимы и выбираются параметром
    ВЫБОР КОГДА &ИспользоватьПродажи ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ

Такой подход, однако, приводит к тому, что в результате мы получаем одну таблицу, но с данными, выбранными по условию. Если же нам нужны две абсолютно независимые секции, то лучше использовать программный вывод.

Выбор подходящего решения

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

  1. Для построчного объединения однотипных данных используйте "Объединение".
  2. Для связывания данных по ключу и получения единой, более широкой структуры применяйте "Соединение".
  3. Если требуется полный контроль над логикой получения и вывода данных, особенно для сложных макетов "на бланке" или данных из нестандартных источников, ваш выбор — программное формирование отчета с использованием набора данных "Объект".

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

← К списку