Как в СКД передать таблицу значений для объединения с данными из запроса и последующей группировки?

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

Часто при разработке отчетов на Системе компоновки данных (СКД) возникает задача: объединить данные, полученные из информационной базы, с данными из внешнего источника, например, из файла Excel или веб-сервиса, которые представлены в виде таблицы значений. При этом требуется не просто вывести их одним списком, а сгруппировать по общим измерениям и рассчитать итоги. Разберем два основных способа решения этой задачи.

Способ 1. Использование набора данных "Объект" и объединения (классический метод)

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

Проанализируем по шагам, как это реализовать.

  1. Создание набора данных-запроса. В схеме компоновки данных на закладке "Наборы данных" создайте "Набор данных - Запрос". Напишите обычный запрос, который получает необходимые данные из информационной базы. Например, остатки товаров.

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

    Например, если в запросе есть поля Номенклатура, Характеристика и КоличествоОстаток, то и в наборе-объекте нужно создать поля с точно такими же именами и соответствующими типами.

  3. Создание набора-объединения. Теперь, когда у нас есть два источника, их нужно "склеить". Для этого создадим третий набор данных типа "Объединение". В настройках этого набора добавьте два ранее созданных набора: запрос и объект. СКД автоматически свяжет поля с одинаковыми именами.

  4. Настройка группировок и ресурсов. Это ключевой момент, который часто вызывает вопросы. Простое объединение наборов лишь добавит строки из таблицы значений к результату запроса. Чтобы данные сгруппировались и просуммировались, необходимо настроить структуру отчета. Перейдем на закладку "Настройки":

    • Удалите стандартную группировку "Детальные записи", если она не нужна.
    • Добавьте новую группировку по тем полям, которые являются измерениями (например, Номенклатура, Характеристика).
    • Перейдите на закладку "Ресурсы" и укажите, какие числовые поля нужно агрегировать. Например, для поля КоличествоОстаток укажите выражение Сумма(КоличествоОстаток).

    Именно эти настройки заставят СКД просуммировать данные из обоих источников по одинаковым значениям измерений.

  5. Программная передача таблицы значений. Последний шаг — передать нашу таблицу значений в СКД во время формирования отчета. Это делается программно, обычно в обработчике события ПриКомпоновкеРезультата формы отчета. Для сокращения объёма кода и упрощения компоновки можно использовать общий модуль-обёртку для программной работы с СКД.

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

    Посмотрим на пример кода:

    
    Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
        
        СтандартнаяОбработка = Ложь;
        
        // Предположим, что у нас есть функция, которая возвращает ТЗ с внешними данными
        // Структура ТЗ должна совпадать с полями, описанными в наборе данных-объекте
        ВнешниеДанныеТЗ = ПолучитьВнешниеДанные(); 
        
        ВнешниеНаборы = Новый Структура;
        // "ВнешниеОстатки" - это имя, которое вы задали для набора данных-объекта в СКД
        ВнешниеНаборы.Вставить("ВнешниеОстатки", ВнешниеДанныеТЗ); 
        
        // Получаем настройки и схему компоновки
        Настройки = КомпоновщикНастроек.ПолучитьНастройки();
        СхемаКомпоновкиДанных = ПолучитьСхемуКомпоновкиДанных();
        ДанныеРасшифровки = Новый ДанныеРасшифровкиКомпоновкиДанных;
        
        // Формируем макет
        КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
        МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
        
        // Выполняем компоновку с передачей внешних данных
        ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
        ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, ВнешниеНаборы, ДанныеРасшифровки);
        
        // Выводим результат в табличный документ
        ДокументРезультат.Очистить();
        ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
        ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
        ПроцессорВывода.Вывести(ПроцессорКомпоновки);
        
    КонецПроцедуры
    

Способ 2. Использование Менеджера временных таблиц (современный метод)

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

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

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

    Это делается с помощью небольшого отдельного запроса.

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

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

    
    ВЫБРАТЬ
        Данные.Номенклатура,
        Данные.Характеристика,
        СУММА(Данные.КоличествоОстаток) КАК КоличествоОстаток
    ИЗ
        (ВЫБРАТЬ
            ТоварыНаСкладахОстатки.Номенклатура КАК Номенклатура,
            ТоварыНаСкладахОстатки.Характеристика КАК Характеристика,
            ТоварыНаСкладахОстатки.ВНаличииОстаток КАК КоличествоОстаток
        ИЗ
            РегистрНакопления.ТоварыНаСкладах.Остатки КАК ТоварыНаСкладахОстатки
    
        ОБЪЕДИНИТЬ ВСЕ
    
        ВЫБРАТЬ
            ВТ_ВнешниеДанные.Номенклатура,
            ВТ_ВнешниеДанные.Характеристика,
            ВТ_ВнешниеДанные.КоличествоОстаток
        ИЗ
            ВТ_ВнешниеДанные) КАК Данные
    
    СГРУППИРОВАТЬ ПО
        Данные.Номенклатура,
        Данные.Характеристика
    

    Как видим, вся логика — и объединение через ОБЪЕДИНИТЬ ВСЕ, и агрегация через СУММА() и СГРУППИРОВАТЬ ПО — находится в одном месте. Это делает схему отчета гораздо проще и нагляднее.

Преимущества метода с Менеджером временных таблиц:

Таким образом, если версия вашей платформы позволяет, рекомендуется использовать второй метод с МенеджеромВременныхТаблиц как более современный и мощный инструмент.

← На главную