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