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