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