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