При работе с Системой компоновки данных (СКД) программисты часто сталкиваются с необходимостью объединить несколько строковых полей в одну строку с использованием определенного разделителя. Для этого в языке выражений СКД предусмотрена функция СоединитьСтроки. Однако стандартное поведение этой функции иногда преподносит сюрпризы: если одно из объединяемых полей оказывается пустым или содержит NULL, в итоговой строке могут появиться «лишние» разделители, например, "; ;" или ", ,". Это портит внешний вид отчета и делает данные трудночитаемыми.
В этой статье мы подробно рассмотрим, почему так происходит, и разберем несколько эффективных способов очистки результата от пустых значений, начиная от простых выражений в вычисляемых полях и заканчивая программными методами в общих модулях.
Прежде чем переходить к решениям, проанализируем ситуацию. Важно понимать различие в работе функции СоединитьСтроки в разных частях СКД:
СоединитьСтроки(Наименование), СКД перебирает записи в группировке. Если поле Наименование в какой-то записи равно NULL, функция просто игнорирует эту строку и не добавляет лишний разделитель.ТаблицаЗначений(Поле1, Поле2, Поле3). В этом случае вы принудительно создаете коллекцию элементов. Если Поле2 пустое, оно все равно попадает в коллекцию как элемент. Функция СоединитьСтроки видит три элемента и честно ставит разделители между ними, даже если второй элемент — пустая строка.Рассмотрим основные способы борьбы с этой проблемой.
Самый быстрый способ, не требующий изменения структуры запроса — это постобработка уже собранной строки. Мы можем использовать функцию СтрЗаменить непосредственно в выражении СКД. Рассмотрим пример, когда мы соединяем три поля: Сотрудник, ПричинаЗаписи и Комментарий.
Проанализируем выражение, которое позволяет избавиться от двойных разделителей:
СтрЗаменить(
СоединитьСтроки(
ТаблицаЗначений(Сотрудник, ПричинаЗаписи, Комментарий),
";",
"; "
),
"; ;",
";"
)
В данном случае мы сначала собираем строку, а затем ищем комбинации пустых значений, разделенных точкой с запятой, и заменяем их на одиночный разделитель. Однако этот метод имеет изъян: если пустое значение окажется в самом начале или в самом конце, СтрЗаменить может не справиться с краевыми разделителями. Поэтому рассмотрим более надежные варианты.
Выясним важную техническую деталь: функция СоединитьСтроки во многих случаях лучше обрабатывает NULL, чем пустые строки "". Если ваши данные приходят из запроса, мы можем на лету трансформировать пустые строки в NULL. Это позволит агрегатным механизмам СКД «отфильтровать» их автоматически.
Рассмотрим пример реализации в тексте запроса или в выражении поля:
ВЫБОР
КОГДА ФОТ1Категорию = "" ТОГДА NULL
ИНАЧЕ ФОТ1Категорию
КОНЕЦ
Если проделать такую операцию для всех соединяемых полей, то при использовании их в качестве Ресурсов (а не вычисляемых полей), проблема лишних запятых исчезнет сама собой, так как СКД не соединяет NULL-значения.
Если логика объединения строк сложная и количество полей может меняться, лучше всего вынести решение в общий модуль. Это позволит нам использовать всю мощь встроенного языка 1С, включая работу с массивами и строковыми функциями, которые недоступны напрямую в выражениях СКД.
Шаг 1. Создание функции в общем модуле. Создайте серверный общий модуль (например, СерверныеФункцииОтчетов) и добавьте туда следующий код:
Функция СоединитьСтрокиБезПустых(Знач МассивСтрок, Разделитель = "; ") Экспорт
Результат = "";
Для Каждого Стр Из МассивСтрок Цикл
ТекущееЗначение = СокрЛП(Строка(Стр));
Если ПустаяСтрока(ТекущееЗначение) Тогда
Продолжить;
КонецЕсли;
Результат = Результат + ?(ПустаяСтрока(Результат), "", Разделитель) + ТекущееЗначение;
КонецЦикла;
Возврат Результат;
КонецФункции
Шаг 2. Вызов функции в СКД. В вычисляемом поле или ресурсе вызовите вашу функцию, передав в нее массив значений. Для создания массива в СКД удобно использовать функцию ТаблицаЗначений (хотя она возвращает таблицу, для некоторых версий платформы и контекстов это работает) или передавать значения по отдельности.
Посмотрим на пример вызова:
СерверныеФункцииОтчетов.СоединитьСтрокиБезПустых(ТаблицаЗначений(Характер, Категория, Воздух))
Рассмотрим ситуацию, когда нам нужно соединить значения из разных колонок одной строки. Вместо того чтобы мучиться с разделителями в вычисляемом поле, мы можем «развернуть» эти колонки в строки прямо в запросе с помощью оператора ОБЪЕДИНИТЬ ВСЕ.
Проанализируем пример структуры запроса:
ВЫБРАТЬ Ссылка, Характер КАК Значение ИЗ Справочник.Объекты ГДЕ Характер <> ""
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка, Категория ИЗ Справочник.Объекты ГДЕ Категория <> ""
ОБЪЕДИНИТЬ ВСЕ
ВЫБРАТЬ Ссылка, ОткрытыйВоздух ИЗ Справочник.Объекты ГДЕ ОткрытыйВоздух <> ""
После такой подготовки данных в СКД появится поле Значение. Теперь достаточно в Ресурсах написать СоединитьСтроки(Значение, "; ") с группировкой по Ссылка. Поскольку пустые значения мы отсекли еще на этапе запроса условием ГДЕ, результат будет идеально чистым.
Если вы работаете на современной версии платформы, рассмотрите возможность использования функции СтрСоединить. Она работает быстрее, чем СоединитьСтроки, но также требует предварительной подготовки массива. В выражениях СКД (начиная с 8.3.10) она доступна, если выполнение происходит на сервере.
Важный момент: чтобы СтрСоединить не выводила пустые места, массив предварительно нужно очистить от пустых строк. Это опять же возвращает нас к использованию общего модуля, так как в самом выражении СКД эффективно отфильтровать массив штатными средствами довольно сложно.
Выясним, какой метод выбрать в зависимости от ситуации:
Используя эти методы, вы сможете создавать профессиональные и аккуратные отчеты в СКД, в которых информация представлена без лишнего «мусора» в виде пустых разделителей.