Как правильно выгрузить табличный документ с иерархией в Excel и избежать дублирования строк

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

Выгрузка данных из 1С в Excel — одна из самых частых задач, с которыми сталкивается разработчик. Однако при работе с иерархическими структурами и сложными запросами, включающими итоги, часто возникают проблемы: появление пустых строк, дублирование данных или ошибки обращения к свойствам объектов. Рассмотрим подробно, как правильно организовать вывод табличного документа через макет и какие альтернативные способы существуют для упрощения этой задачи.

Разбор проблемы: почему появляются дубли и пустые строки

Проанализируем ситуацию, когда при использовании итогов в запросе данные начинают «удваиваться». Это происходит из-за специфики работы метода Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам). Когда мы строим запрос с конструкцией ИТОГИ ПО..., 1С формирует древовидную структуру, где каждая вышестоящая группировка (итог) содержит в себе детальные записи. Если в коде вывода не разделять обработку итоговой строки и детальной записи, одно и то же значение будет выведено дважды: сначала как заголовок группы, а затем как содержимое этой группы.

Рассмотрим пример некорректного кода, который приводит к дублям:


// Ошибка здесь: итог по ВИ (варианту исполнения) создает лишний уровень
Запрос.Текст = "ВЫБРАТЬ ... ИТОГИ ПО Номенклатура, ВИ"; 

Если «Вариант исполнения» является конечной точкой данных, его не нужно включать в иерархию ИТОГИ ПО. Достаточно оставить итоги только по иерархии самой номенклатуры. Выясним причину ошибки «Значение не является значением объектного типа» при обращении к полям вроде БазоваяЕдИзм. Она возникает, когда выборка находится на уровне иерархического итога (например, папки), где ссылка на конкретную номенклатуру может отсутствовать или поле еще не заполнено для данного уровня группировки.

Решение 1: Правильный программный вывод макета с рекурсией

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

  1. Настройка запроса: Используйте ИТОГИ ПО ... ИЕРАРХИЯ только для тех полей, которые действительно образуют структуру. Остальные данные (характеристики, единицы измерения, штрихкоды) должны выбираться как детальные записи.
  2. Обработка уровней: В рекурсивной функции вывода важно проверять, есть ли у текущей группировки вложенные записи.
  3. Безопасное обращение к свойствам: Перед получением свойств через точку (например, Выборка.Номенклатура.БазоваяЕдИзм), всегда проверяйте тип записи или наличие ссылки.

Рассмотрим оптимизированный пример кода для вывода иерархии:


Процедура ВыгрузитьШаблон()
    Запрос = Новый Запрос;
    Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВариантыИсполнения.Владелец КАК Номенклатура,
    |	ВариантыИсполнения.Ссылка КАК ВИ
    |ИЗ
    |	Справочник.ВариантыИсполнения КАК ВариантыИсполнения
    |ГДЕ
    |	ВариантыИсполнения.Владелец В ИЕРАРХИИ(&Номенклатура)
    |ИТОГИ ПО
    |	Номенклатура ИЕРАРХИЯ";
    
    Запрос.УстановитьПараметр("Номенклатура", СписокНоменклатуры);
    
    РезультатЗапроса = Запрос.Выполнить();
    Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
    
    ТабДок = Новый ТабличныйДокумент;
    Макет = ПолучитьМакет("Макет");
    ОбластьСтрока = Макет.ПолучитьОбласть("Тело");
    
    ТабДок.НачатьАвтогруппировкуСтрок();
    ВывестиСтрокиРекурсивно(ТабДок, ОбластьСтрока, Выборка);
    ТабДок.ЗакончитьАвтогруппировкуСтрок();
    
    ТабДок.Показать();
КонецПроцедуры

Процедура ВывестиСтрокиРекурсивно(ТабДок, ОбластьСтрока, Выборка)
    Пока Выборка.Следующий() Цикл
        // Заполняем параметры области из текущей выборки
        ЗаполнитьЗначенияСвойств(ОбластьСтрока.Параметры, Выборка);
        
        // Выводим строку с указанием уровня (для группировки в 1С и Excel)
        ТабДок.Вывести(ОбластьСтрока, Выборка.Уровень());
        
        // Переходим к следующему уровню вложенности (детальные записи или подгруппы)
        ВыборкаВложенная = Выборка.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);
        ВывестиСтрокиРекурсивно(ТабДок, ОбластьСтрока, ВыборкаВложенная);
    КонецЦикла;
КонецПроцедуры

Решение 2: Использование СКД — самый быстрый способ

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

Рассмотрим преимущества СКД для данной задачи:

Для программного вызова СКД и сохранения в Excel можно использовать следующий алгоритм:


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

ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки);

ТабДок = Новый ТабличныйДокумент;
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ТабДок);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);

// Сохраняем результат
ТабДок.Записать("C:\Temp\Выгрузка.xlsx", ТипФайлаТабличногоДокумента.XLSX);

Оптимизация получения штрихкодов

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

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

Тонкости сохранения в формат Excel

Посмотрим на особенности записи файла. В 1С доступно несколько типов файлов для сохранения.

Важно: Всегда используйте ТипФайлаТабличногоДокумента.XLSX вместо устаревшего XLS. Старый формат имеет жесткое ограничение — не более 65536 строк. Если ваш каталог номенклатуры велик, выгрузка в XLS прервется с ошибкой. Формат XLSX лишен этого недостатка и лучше сохраняет форматирование ячеек (цвета, границы, шрифты).

Также обратите внимание на метод Показать(). Если выгрузка выполняется регламентным заданием или на сервере, этот метод вызовет ошибку, так как на сервере нет пользовательского интерфейса. В таких случаях используйте только метод Записать().

Итоги

Подводя итог, при выгрузке данных в Excel через табличный документ важно следовать правилам:

  1. Использовать ИТОГИ ПО ... ИЕРАРХИЯ только для полей, создающих структуру дерева.
  2. При ручном обходе выборки использовать рекурсию и метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам).
  3. Для сложных отчетов отдавать предпочтение СКД, так как это минимизирует количество ошибок в коде.
  4. Сохранять результат в формате XLSX для поддержки больших объемов данных.

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

← На главную