В современной разработке на платформе 1С:Предприятие 8.3 часто возникает задача использования предварительно подготовленных данных в отчетах СКД. Традиционный метод через «Внешний набор данных» (объект) не всегда эффективен, особенно если эти данные нужно соединять с тяжелыми таблицами базы данных на уровне СУБД. Кроме того, для тех, кто хочет автоматизировать создание самих схем, существует инструмент СКДБилдер, который значительно упрощает программную работу с объектами компоновки. Начиная с версии платформы 8.3.15, у разработчиков появилась возможность передать МенеджерВременныхТаблиц напрямую в процессор компоновки. В этой статье мы подробно разберем, как реализовать этот механизм и избежать распространенной ошибки «Таблица не найдена».
Прежде чем мы перейдем к коду, давайте проанализируем преимущества этого подхода. Когда мы передаем таблицу значений как ВнешнийНаборДанных, система выполняет соединение данных программно на сервере приложений. Если же мы помещаем таблицу значений во временную таблицу и передаем ее через МенеджерВременныхТаблиц, СКД может построить запрос, который выполнится целиком на стороне SQL-сервера. Это один из эффективных методов оптимизации отчетов с набором данных - объект, значительно повышающий производительность на больших объемах данных.
Разберем самую частую причину неудач — отсутствие явного описания типов колонок. Для того чтобы СКД «увидела» таблицу в менеджере, колонки исходной ТаблицаЗначений должны быть строго типизированы. Рассмотрим пример создания такой таблицы:
// Создаем описание типов для колонок
МассивТиповСтрока = Новый Массив;
МассивТиповСтрока.Добавить(Тип("Строка"));
ОписаниеТиповСтрока = Новый ОписаниеТипов(МассивТиповСтрока, , Новый КвалификаторыСтроки(100));
МассивТиповЧисло = Новый Массив;
МассивТиповЧисло.Добавить(Тип("Число"));
ОписаниеТиповЧисло = Новый ОписаниеТипов(МассивТиповЧисло, , , Новый КвалификаторыЧисла(15, 2));
// Инициализируем ТЗ с типами
ОбщаяТаблицаМаршрутов = Новый ТаблицаЗначений;
ОбщаяТаблицаМаршрутов.Колонки.Добавить("Маршрут", ОписаниеТиповСтрока);
ОбщаяТаблицаМаршрутов.Колонки.Добавить("Расстояние", ОписаниеТиповЧисло);
// Заполняем данными (пример)
НоваяСтрока = ОбщаяТаблицаМаршрутов.Добавить();
НоваяСтрока.Маршрут = "Северный путь";
НоваяСтрока.Расстояние = 150.50;
Теперь нам нужно создать МенеджерВременныхТаблиц и поместить туда нашу таблицу с помощью запроса. Выясним важный момент: имя временной таблицы, которое мы укажем в запросе ПОМЕСТИТЬ, должно в точности совпадать с именем, которое мы будем использовать в схеме компоновки данных.
МВТ = Новый МенеджерВременныхТаблиц;
ЗапросВТ = Новый Запрос;
ЗапросВТ.МенеджерВременныхТаблиц = МВТ;
// Используем явные псевдонимы для полей
ЗапросВТ.Текст =
"ВЫБРАТЬ
| ТЗ.Маршрут КАК Маршрут,
| ТЗ.Расстояние КАК Расстояние
|ПОМЕСТИТЬ ВТ_ОбщаяТаблицаМаршрутов
|ИЗ
| &ОбщаяТаблицаМаршрутов КАК ТЗ";
ЗапросВТ.УстановитьПараметр("ОбщаяТаблицаМаршрутов", ОбщаяТаблицаМаршрутов);
ЗапросВТ.Выполнить();
На этом этапе мы сталкиваемся с тем, что Конструктор запроса СКД не видит таблицу ВТ_ОбщаяТаблицаМаршрутов, так как она создается только в момент выполнения кода. Для предварительной отладки таких запросов удобно использовать модифицированную консоль запросов, которая полноценно поддерживает пакетные запросы и временные таблицы. Рассмотрим, как правильно составить запрос в СКД:
ВЫРАЗИТЬ для полей, чтобы гарантировать понимание типов системой компоновки.
ВЫБРАТЬ
ВЫРАЗИТЬ(ВТ.Маршрут КАК СТРОКА(100)) КАК Маршрут,
ВЫРАЗИТЬ(ВТ.Расстояние КАК ЧИСЛО(15, 2)) КАК Расстояние
ИЗ
ВТ_ОбщаяТаблицаМаршрутов КАК ВТ
Если конфигуратор выдает ошибку при сохранении, можно временно добавить в начало запроса создание фиктивной временной таблицы с таким же именем, сохранить поля, а затем удалить лишний код, оставив только обращение к ВТ_ОбщаяТаблицаМаршрутов.
Проанализируем финальный этап — программный вывод отчета в модуле объекта или формы. Здесь ключевым является метод Инициализировать объекта ПроцессорКомпоновкиДанных. Нам нужно передать наш МВТ в качестве шестого параметра. Такой подход позволяет гибко управлять данными.
// Получаем настройки и макет
Настройки = КомпоновщикНастроек.ПолучитьНастройки();
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
// Инициализируем процессор компоновки
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
// Параметры метода:
// 1. МакетКомпоновки
// 2. ВнешниеНаборыДанных (может быть пустая Структура)
// 3. ДанныеРасшифровки
// 4. ВозможностьИспользованияВнешнихФункций
// 5. ПроверитьДоступностьПолей
// 6. МенеджерВременныхТаблиц <-- Вот наш ключ!
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, Новый Структура, ДанныеРасшифровки, Ложь, Ложь, МВТ);
// Далее стандартный вывод в табличный документ
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(Результат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
При программном выводе вы также можете столкнуться с необходимостью более тонкой настройки оформления, например, когда требуется программное изменение заголовка группировки отчета, или если ваша логика предполагает использование двух разных схем в одном отчете СКД.
Разобравшись с примерами кода, выделим основные причины, по которым механизм может не сработать:
Инициализировать просто игнорируется.МенеджерВременныхТаблиц должен существовать в памяти до завершения работы процессора компоновки. Если переменная МВТ определена локально и процедура завершилась до вывода данных, таблица может быть удалена.ТаблицаЗначений не было передано ОписаниеТипов, 1С присвоит ей тип Неопределено или составной тип, что часто приводит к сбоям в СКД.Таким образом, использование МенеджераВременныхТаблиц в связке с СКД — это мощный инструмент оптимизации. Основной секрет успеха заключается в строгой типизации данных еще на этапе формирования таблицы значений и правильном использовании оператора ВЫРАЗИТЬ в самом запросе схемы компоновки.