В практике разработки на платформе 1С:Предприятие 8 часто возникает задача: необходимо вывести в отчет данные, которые нельзя получить одним простым запросом. Например, данные могут быть результатом сложных расчетов, получены из внешних систем через COM-соединение или собраны из нескольких не связанных между собой регистров. В таких случаях программист формирует Таблицу Значений (ТЗ). Рассмотрим, как правильно интегрировать эту таблицу в отчет, особенно если вы работаете в конфигурациях на обычных формах (УТ 10.3, УПП 1.3), где традиционно используется Универсальный отчет на базе Построителя отчета.
Проанализируем ситуацию, с которой столкнулся автор темы. Попытка передать таблицу значений в текст запроса Построителя отчета через менеджер временных таблиц (МВТ) обречена на провал. Выясним причину: объект ПостроительОтчета, в отличие от объекта Запрос, имеет упрощенную логику работы с источниками. Он предназначен для динамического формирования текста запроса на основе метаданных, но он не поддерживает работу с Менеджером временных таблиц в том виде, в котором мы привыкли его использовать.
Если мы напишем в тексте запроса для построителя что-то вроде ВЫБРАТЬ * ИЗ &МояТЗ КАК МояТЗ, система выдаст ошибку, так как построитель не сможет инициализировать описание полей этого источника до начала выполнения. Рассмотрим подробнее, как обойти это ограничение или выбрать более современный инструмент.
Если по каким-то причинам мы обязаны использовать именно старый Универсальный отчет, нам придется изменить логику его работы. Вместо того чтобы пытаться внедрить ТЗ в текст запроса внутри процедуры УстановитьНачальныеНастройки, мы можем попробовать установить ИсточникДанных для построителя напрямую. Однако это потребует серьезной переработки модуля отчета, так как стандартный механизм УниверсальныйОтчет.СформироватьОтчет() ожидает заполненный текст запроса.
Важный момент, который стоит запомнить: если вы передаете таблицу в любой механизм отчетов, колонки таблицы должны быть строго типизированы. Рассмотрим пример кода для создания такой таблицы:
ДанныеДляОтчета = Новый ТаблицаЗначений;
ДанныеДляОтчета.Колонки.Добавить("Номенклатура", Новый ОписаниеТипов("СправочникСсылка.Номенклатура"));
ДанныеДляОтчета.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)));
Без явного указания ОписаниеТипов система компоновки или построитель не смогут определить доступные поля для группировок и отборов.
Как справедливо заметили участники обсуждения, использование СКД является наиболее правильным и надежным способом решения задачи. В СКД предусмотрен штатный механизм для работы с внешними таблицами — Набор данных - объект. Разберем по шагам, как это реализовать.
ВнешняяТаблицаДанных.СУММА(Остаток)) и структуру отчета.Теперь проанализируем программную часть. Нам нужно передать сформированную ТЗ в компоновщик перед выводом отчета. Обычно это делается в модуле объекта отчета в процедуре ПриКомпоновкеРезультата.
Рассмотрим пример реализации, объединяющий получение данных (например, через COM) и их вывод в СКД:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь; // Отключаем стандартный вывод
// 1. Формируем таблицу значений (здесь может быть ваш сложный алгоритм или COM-запрос)
ТаблицаВнешнихДанных = СформироватьВнешнююТЗ();
// 2. Подготавливаем структуру внешних наборов данных
// Ключ структуры должен СОВПАДАТЬ с именем объекта в схеме СКД
ВнешниеНаборыДанных = Новый Структура;
ВнешниеНаборыДанных.Вставить("ВнешняяТаблицаДанных", ТаблицаВнешнихДанных);
// 3. Выполняем компоновку
СхемаКомпоновкиДанных = ПолучитьМакет("ОсновнаяСхемаКомпоновкиДанных");
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
ПроцессорКомпоновкиДанных = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновкиДанных.Инициализировать(МакетКомпоновки, ВнешниеНаборыДанных, ДанныеРасшифровки);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновкиДанных);
КонецПроцедуры
Посмотрим на ситуацию, описанную в сообщении №20: пользователь жалуется, что в итогах вместо суммы остатков выводится число "1". Это типичная проблема при работе с внешними наборами данных. Выясним причину: СКД не знает автоматически, является ли ваше поле "Остаток" ресурсом или просто числовым описанием.
Чтобы исправить это, выполним следующие действия:
СУММА(ИмяПоля). Если там стоит Количество(...), то отчет будет считать строки, а не значения.Проанализируем фрагмент кода из сообщения №12. Автор использует V81.ComConnector для получения данных из другой базы. Это ресурсоемкая операция. Если данных много, использование ValueToStringInternal и ЗначениеИзСтрокиВнутр для передачи таблицы через COM — не самый быстрый путь. Рассмотрим альтернативу: если обе базы находятся на одном сервере, эффективнее использовать прямые SQL-запросы или веб-сервисы. Однако, если мы ограничены COM-соединением, старайтесь максимально фильтровать данные на стороне "источника", чтобы передавать в основную базу уже свернутую и подготовленную таблицу значений.
Подведем итог: использование Построителя отчета для внешних ТЗ в 1С — это путь, полный костылей и ограничений. Переход на СКД с набором данных типа Объект решает проблему архитектурно правильно, обеспечивая гибкость настроек, корректные итоги и возможность дальнейшего масштабирования отчета.