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