При разработке отчетов в Системе компоновки данных (СКД) разработчики часто сталкиваются с необходимостью красивого оформления выводимых данных. Классический пример — формирование динамических заголовков колонок или представлений периодов. Например, когда на основе числового параметра &Год (например, 2024) нужно получить строковое представление сезона: "Зима 2023/2024" или "Лето 2024".
Исторически в языке запросов «1С:Предприятия» отсутствовала прямая возможность преобразования числа в строку. Попытки использовать конструкцию ВЫРАЗИТЬ(Число КАК СТРОКА) вызывают ошибку компиляции запроса, а функция ПРЕДСТАВЛЕНИЕ() предназначена исключительно для получения текстового описания ссылочных типов на стороне клиента и не позволяет производить операции конкатенации (сложения) строк на уровне базы данных.
В данной статье мы подробно разберем несколько эффективных способов решения этой задачи: от классического использования вычисляемых полей СКД до революционных возможностей современных версий платформы и применения функций общих модулей.
Если отчет должен быть совместим со старыми версиями платформы «1С:Предприятие» (ниже версии 8.3.20), то самым надежным и гибким решением будет использование вкладки «Вычисляемые поля» в схеме компоновки данных.
Вычисляемые поля обрабатываются платформой уже после выполнения запроса, на этапе компоновки результата. В выражениях этих полей доступен практически весь спектр функций встроенного языка 1С, включая функции работы со строками и форматированием.
Рассмотрим по шагам, как реализовать такую логику:
ПредставлениеПериода) и путь к данным (под этим именем поле будет доступно для вывода в отчет).Проанализируем пример кода, предложенный автором темы на форуме:
Выбор когда Интервал = "ОСЕНЬ"
Тогда "ОСЕНЬ " + Строка(Формат(&Год,"ЧГ=0"))
когда Интервал = "ЛЕТО"
Тогда "ЛЕТО " + Строка(Формат(&Год,"ЧГ=0"))
когда Интервал = "ВЕСНА"
Тогда "ВЕСНА " + Строка(Формат(&Год,"ЧГ=0"))
когда Интервал = "ЗИМА_ДО"
Тогда "ЗИМА " + Строка(Формат(&Год-1,"ЧГ=0")) + "/" + Строка(Формат(&Год,"ЧГ=0"))
когда Интервал = "ЗИМА_ПОСЛЕ"
Тогда "ЗИМА " + Строка(Формат(&Год,"ЧГ=0")) + "/" + Строка(Формат(&Год+1,"ЧГ=0"))
Конец
Этот код отлично решает задачу, но его можно оптимизировать. Обратите внимание на конструкцию Строка(Формат(&Год, "ЧГ=0")). Функция Формат() во встроенном языке 1С изначально возвращает значение типа Строка. Дополнительное обертывание в функцию Строка() здесь является избыточным и лишь тратит ресурсы процессора. Также важно использовать форматную строку ЧГ=0 (Численные Группы = 0), чтобы платформа не разделяла тысячи пробелами (чтобы не получилось "2 018" вместо "2018").
Оптимизированный вариант выражения будет выглядеть следующим образом:
Выбор когда Интервал = "ОСЕНЬ"
Тогда "ОСЕНЬ " + Формат(&Год,"ЧГ=0")
когда Интервал = "ЛЕТО"
Тогда "ЛЕТО " + Формат(&Год,"ЧГ=0")
когда Интервал = "ВЕСНА"
Тогда "ВЕСНА " + Формат(&Год,"ЧГ=0")
когда Интервал = "ЗИМА_ДО"
Тогда "ЗИМА " + Формат(&Год-1,"ЧГ=0") + "/" + Формат(&Год,"ЧГ=0")
когда Интервал = "ЗИМА_ПОСЛЕ"
Тогда "ЗИМА " + Формат(&Год,"ЧГ=0") + "/" + Формат(&Год+1,"ЧГ=0")
Конец
Если вы работаете на современной платформе «1С:Предприятие» версии 8.3.20 и выше, необходимость в переносе логики в вычисляемые поля СКД отпадает. Разработчики платформы совершили долгожданную революцию, добавив полноценную поддержку строковых функций непосредственно в язык запросов.
Теперь прямо в тексте запроса (в блоке ВЫБРАТЬ) мы можем использовать следующие функции:
СТРОКА() — преобразует примитивные типы (числа, даты, булево) в строку.СОКРЛП(), СОКРЛ(), СОКРП() — удаляют лишние пробелы.ЛЕВ(), ПРАВ() — позволяют извлекать части строк.Посмотрим, как будет выглядеть фрагмент запроса с формированием нашего представления:
ВЫБРАТЬ
ВЫБОР
КОГДА ТаблицаПериодов.Интервал = "ЗИМА_ДО"
ТОГДА "Зима " + СТРОКА(ТаблицаПериодов.Год - 1) + "/" + СТРОКА(ТаблицаПериодов.Год)
ИНАЧЕ "Лето " + СТРОКА(ТаблицаПериодов.Год)
КОНЕЦ КАК ПредставлениеСезона
ИЗ
ТаблицаПериодов КАК ТаблицаПериодов
Этот способ является наиболее производительным, так как преобразование типов и конкатенация выполняются непосредственно на стороне СУБД (SQL-сервера) при выборке данных, а СКД получает уже готовые строковые поля для вывода.
Что делать, если алгоритм формирования представления периода слишком сложный, содержит много условий или требует обращения к сторонней бизнес-логике базы данных? Писать огромные конструкции ВЫБОР КОГДА в вычисляемых полях СКД становится неудобно и трудночитаемо.
В этом случае отличным архитектурным решением станет делегирование расчетов экспортной функции общего модуля 1С.
Выполним это по шагам:
Шаг 1. Создание общего модуля
Создадим (или откроем существующий) общий модуль, например, с именем РаботаСОтчетамиВызовСервера. Убедитесь, что в свойствах модуля установлены флажки «Сервер» и «Вызов сервера» (или «Клиент» в зависимости от контекста выполнения отчета).
Шаг 2. Написание функции преобразования
Добавим в модуль экспортную функцию:
Функция ПолучитьПредставлениеСезона(Интервал, Год) Экспорт
Если Интервал = "ЗИМА_ДО" Тогда
Возврат СтрШаблон("Зима %1/%2", Формат(Год - 1, "ЧГ=0"), Формат(Год, "ЧГ=0"));
ИначеЕсли Интервал = "ЗИМА_ПОСЛЕ" Тогда
Возврат СтрШаблон("Зима %1/%2", Формат(Год, "ЧГ=0"), Формат(Год + 1, "ЧГ=0"));
Иначе
Возврат СтрШаблон("%1 %2", Интервал, Формат(Год, "ЧГ=0"));
КонецЕсли;
КонецФункции
Шаг 3. Вызов функции в СКД
Возвращаемся в схему компоновки данных на вкладку «Вычисляемые поля». В поле «Выражение» для нашего поля прописываем обращение к созданной функции общего модуля:
РаботаСОтчетамиВызовСервера.ПолучитьПредставлениеСезона(Интервал, &Год)
Важное примечание по безопасности: Чтобы СКД корректно вызвала внешнюю функцию общего модуля, в модуле объекта отчета (в событии ПриКомпоновкеРезультата) необходимо явно разрешить использование внешних функций компоновщика макета:
Процедура ПриКомпоновкеРезультата(ДокументРезультат, ДанныеРасшифровки, СтандартнаяОбработка)
СтандартнаяОбработка = Ложь;
КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
// Разрешаем использование функций общих модулей в СКД
ИнициализаторМакета = Новый ИнициализаторМакетаКомпоновкиДанных;
ИнициализаторМакета.ИспользоватьВнешниеФункции = Истина;
МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, НастройкиКомпоновкиДанных, ДанныеРасшифровки);
ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки, Истина);
ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
ПроцессорВывода.УстановитьДокумент(ДокументРезультат);
ПроцессорВывода.Вывести(ПроцессорКомпоновки);
КонецПроцедуры
Иногда лучшим решением проблемы является ее предотвращение. Как справедливо заметили участники форума в сообщениях №5 и №8, если параметр года нужен только для вывода красивого заголовка, почему бы изначально не передавать его в отчет в виде готового текстового значения? Например, передавать параметр &ГодСтрока со значением "2018".
Однако автор резонно возразил (сообщение №7), что исходный числовой параметр года активно используется в запросе для расчета дат, получения остатков регистров накопления и выполнения математических операций внутри виртуальных таблиц.
В такой ситуации рекомендуется использовать связанные параметры:
&Год).&ГодСтрока), но снимаем у него флаг «Доступен» на вкладке «Параметры» в СКД, чтобы пользователь его не видел.Формат(&Год, "ЧГ=0").Таким образом, пользователь выбирает понятное число, система автоматически преобразует его в нужную строку, и мы можем использовать строковую переменную в запросе без лишних вычислений «на лету».
Выбор конкретного метода зависит от версии вашей технологической платформы «1С:Предприятие» и сложности бизнес-логики отчета. Для простых отчетов на новых платформах оптимально использовать функцию СТРОКА() в самом запросе. Для сложных комплексных расчетов и старых версий платформы лучшим решением остаются вычисляемые поля СКД с привлечением функций общих модулей.