Мы с вами сталкиваемся с достаточно распространенной задачей в разработке отчетов на Системе Компоновки Данных (СКД) в 1С: как эффективно объединить или вывести информацию, полученную из нескольких независимых источников или наборов данных. Нередко возникает ситуация, когда эти наборы имеют разное количество строк, различную структуру или их объединение стандартными средствами СКД приводит к нежелательному перемножению данных. Давайте вместе разберемся в доступных подходах и выберем наиболее подходящее решение для вашей конкретной ситуации.
Первый и самый очевидный способ, который предоставляет СКД для работы с несколькими наборами данных, это их объединение. Этот механизм аналогичен оператору UNION ALL в SQL-запросах и предназначен для вывода всех записей из каждого набора данных в единую структуру.
Для корректного использования этого метода важно соблюдать несколько условий:
Этот способ идеально подходит, когда мы хотим показать все записи из разных источников в одном списке. Например, если нам нужно получить единый список всех поступлений и продаж номенклатуры, или список всех движений по дебету и кредиту счета. После объединения, если требуется свернуть задвоенные строки (например, когда один и тот же товар присутствует в обоих наборах, но мы хотим видеть его только один раз с суммарными показателями), мы можем использовать группировку по соответствующему полю в настройках СКД.
Рассмотрим пример, когда нам нужно объединить данные о продажах и возвратах:
ВЫБРАТЬ
Продажи.Номенклатура КАК Номенклатура,
Продажи.Количество КАК Количество,
Продажи.Сумма КАК Сумма,
"Продажа" КАК ТипОперации
ИЗ
Документ.РеализацияТоваровУслуг.Товары КАК Продажи
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ
Возвраты.Номенклатура КАК Номенклатура,
-Возвраты.Количество КАК Количество,
-Возвраты.Сумма КАК Сумма,
"Возврат" КАК ТипОперации
ИЗ
Документ.ВозвратТоваровОтПокупателя.Товары КАК Возвраты
Этот запрос мы можем использовать как основу для одного набора данных, или же создать два отдельных набора, а затем объединить их через механизм Объединение СКД, убедившись, что поля Номенклатура, Количество, Сумма и ТипОперации присутствуют и имеют одинаковые названия в обоих наборах.
Второй мощный инструмент СКД — это соединение наборов данных. Этот подход позволяет связать несколько наборов данных между собой по аналогии с оператором JOIN в SQL-запросах.
Связи наборов данных обычно реализуются как левое внешнее соединение. Это означает, что все записи из родительского (левого) набора данных будут отображены, а из зависимого (правого) набора — только те, которые соответствуют заданному условию связи. Если соответствия не найдено, поля из правого набора будут пустыми (NULL).
Соединение наборов данных удобно использовать в следующих случаях:
При соединении наборов данных могут возникать особенности в расчете итогов ресурсов, которые отличаются от соединения таблиц на уровне запроса. Например, если в одном наборе данных есть несколько строк, соответствующих одной строке другого набора, ресурсы могут задваиваться. Для обхода этих особенностей может потребоваться использование функции языка выражений СКД ВычислитьВыражениеСГруппировкойМассив. Эта функция позволяет агрегировать значения по определенным группировкам до того, как они будут соединены, или после соединения, но с учетом уникальных значений.
Для уменьшения количества строк во втором наборе данных при соединении, что может быть полезно для производительности, мы можем использовать отбор по параметру в запросе дочернего набора.
Иногда стандартные механизмы СКД — объединение и соединение — оказываются недостаточными. Это происходит, когда данные нужно получить по очень сложной логике, из внешних систем, или когда требуется вывести две независимые таблицы с разным количеством строк, которые не должны быть напрямую связаны, но должны отображаться в одном отчете. В таких случаях на помощь приходит программное формирование отчета, часто с использованием набора данных типа "Объект".
Мы прибегаем к этому подходу, если:
При использовании набора данных типа "Объект" мы:
ПриКомпоновкеРезультата модуля отчета. Мы можем заполнить таблицу значений в коде 1С и передать ее в набор данных "Объект".Рассмотрим пример концептуального кода для заполнения набора данных "Объект":
// В модуле отчета, в процедуре ПриКомпоновкеРезультата
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
// Отключаем стандартную обработку, так как мы будем выводить результат программно
СтандартнаяОбработка = Ложь;
// Создаем таблицу значений, которая будет источником данных
Перем ТаблицаДанных;
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Поле1", Новый ОписаниеТипов("Строка"));
ТаблицаДанных.Колонки.Добавить("Поле2", Новый ОписаниеТипов("Число"));
// Заполняем таблицу значений данными
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Поле1 = "Значение 1";
НоваяСтрока.Поле2 = 100;
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Поле1 = "Значение 2";
НоваяСтрока.Поле2 = 200;
// Получаем процессор компоновки данных
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(СхемаКомпоновкиДанных, КомпоновщикМакета.ПолучитьМакет(), ДанныеРасшифровки);
// Устанавливаем нашу таблицу значений в качестве источника для набора данных "Объект"
// Предполагается, что в СКД есть набор данных с именем "НаборОбъект"
ПроцессорКомпоновки.УстановитьДанныеНабораДанных("НаборОбъект", ТаблицаДанных);
// Далее мы можем либо использовать процессор вывода СКД для частичного вывода,
// либо полностью формировать табличный документ вручную.
// Если мы хотим полностью контролировать вывод, то используем:
// ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
// ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
// ПроцессорВывода.Вывести(ПроцессорКомпоновки);
// Но чаще всего для "отчетов на бланке" мы будем работать с макетами и областями.
// Пример программного вывода (концептуально)
Макет = ПолучитьМакет("МакетОтчета"); // Получаем собственный макет
ОбластьЗаголовок = Макет.ПолучитьОбласть("Заголовок");
ОбластьЗаголовок.Параметры.ТекстЗаголовка = "Мой Программный Отчет";
ДокументРезультат.Вывести(ОбластьЗаголовок);
ОбластьШапкаТаблицы = Макет.ПолучитьОбласть("ШапкаТаблицы");
ДокументРезультат.Вывести(ОбластьШапкаТаблицы);
Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
ОбластьСтрока = Макет.ПолучитьОбласть("СтрокаТаблицы");
ОбластьСтрока.Параметры.Поле1 = СтрокаТЗ.Поле1;
ОбластьСтрока.Параметры.Поле2 = СтрокаТЗ.Поле2;
ДокументРезультат.Вывести(ОбластьСтрока);
КонецЦикла;
КонецПроцедуры
Этот подход дает нам максимальную гибкость и полный контроль над формированием отчета, что незаменимо для создания сложных, нестандартных печатных форм и отчетов, которые СКД "в чистом виде" реализовать не может.
Иногда задача не сводится к простому объединению или соединению. Что, если нам нужно вывести две совершенно независимые таблицы с разным количеством строк, объединенные одним логическим полем, но без перемножения строк? Например, нам нужен отчет, где в одной части выводятся данные о продажах, а в другой — о закупках, и эти части не должны влиять друг на друга в плане количества строк, но должны быть представлены в одном документе.
В таких случаях мы можем использовать СКД исключительно как мощный инструмент для получения и агрегации данных. Мы формируем отдельные наборы данных запросами, получаем их результаты в виде таблиц значений (или других коллекций), а затем полностью программно выводим эти данные в табличный документ. Процессор вывода СКД в этом случае не используется. Это позволяет нам:
Если задача состоит в том, чтобы по условию выводить данные из одной или другой таблицы (но не одновременно), мы можем использовать параметры отчета типа "Булево". В зависимости от значения такого параметра, мы можем либо активировать определенный набор данных, либо использовать условные выражения в запросах для выбора нужных полей.
Например, в запросе мы можем использовать конструкцию ВЫБОР КОГДА:
ВЫБРАТЬ
ВЫБОР КОГДА &ИспользоватьПродажи ТОГДА Продажи.Номенклатура ИНАЧЕ Возвраты.Номенклатура КОНЕЦ КАК Номенклатура,
ВЫБОР КОГДА &ИспользоватьПродажи ТОГДА Продажи.Количество ИНАЧЕ Возвраты.Количество КОНЕЦ КАК Количество
ИЗ
(ВЫБРАТЬ Номенклатура, Количество ИЗ Документ.РеализацияТоваровУслуг.Товары) КАК Продажи,
(ВЫБРАТЬ Номенклатура, Количество ИЗ Документ.ВозвратТоваровОтПокупателя.Товары) КАК Возвраты
ГДЕ
// Здесь условие, которое связывает Продажи и Возвраты, если нужно их сопоставить
// Или просто выбираем один из наборов, если они независимы и выбираются параметром
ВЫБОР КОГДА &ИспользоватьПродажи ТОГДА ИСТИНА ИНАЧЕ ЛОЖЬ КОНЕЦ
Такой подход, однако, приводит к тому, что в результате мы получаем одну таблицу, но с данными, выбранными по условию. Если же нам нужны две абсолютно независимые секции, то лучше использовать программный вывод.
Как мы видим, задача вывода данных из разных наборов данных в отчете СКД имеет несколько решений, каждое из которых подходит для своей ситуации:
Всегда анализируйте требования к отчету и особенности данных, чтобы выбрать наиболее эффективный и поддерживаемый подход. Часто оптимальным решением является комбинирование возможностей СКД для получения данных и программного кода для их финальной компоновки и вывода.
← К списку