Как вывести несколько строк с одинаковым именем в кросс-таблице СКД без объединения?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с Системой компоновки данных (СКД) разработчики часто сталкиваются со специфическим поведением кросс-таблиц. Когда мы пытаемся вывести данные в формате двумерной таблицы (где строки — это одни аналитические разрезы, а колонки — другие), СКД автоматически группирует и агрегирует записи. Если в исходных данных для одной и той же строки присутствует несколько разных значений для одной и той же колонки, СКД не станет создавать новую строку по умолчанию. Вместо этого система либо просуммирует значения, либо выведет только одно из них (в зависимости от настроек ресурса), оставив всего одну строку на экране.

В этой статье мы подробно разберем, почему так происходит, и рассмотрим проверенные практические методы решения этой проблемы, включая программную подготовку данных и тонкую настройку схемы компоновки данных.

Выясняем причину: почему СКД «схлопывает» строки?

Давайте проанализируем ситуацию на примере исходных данных, которые использовал автор темы. Представим таблицу значений со следующей структурой:

  1. Строка 1: Строки = "Хреновина1", Колонки = "Парам1", Значение = "12"
  2. Строка 2: Строки = "Хреновина1", Колонки = "Парам1", Значение = "13"
  3. Строка 3: Строки = "Хреновина1", Колонки = "Парам2", Значение = "17"

Когда мы настраиваем структуру отчета типа Таблица в СКД, где в качестве строк указано поле Строки, а в качестве колонок — поле Колонки, система формирует уникальные ключи группировок. Для строк уникальным ключом становится значение поля Строки. Поскольку у нас три записи, и во всех трех поле содержит значение "Хреновина1", СКД создает ровно одну строку в результирующем табличном документе.

Далее система пытается распределить ресурсы по колонкам. Для колонки "Парам1" у нас есть два конфликтующих значения: "12" и "13". Если поле Значение определено как ресурс с функцией Сумма, мы получим "25". Если функция ресурса — Максимум, то отобразится "13". Но цель автора — получить две физические строки на экране, чтобы детально показать обе записи:

  1. Первая строка: Хреновина1 | Парам1 = 12 | Парам2 = 17
  2. Вторая строка: Хреновина1 | Парам1 = 13 | Парам2 = 0 (или пусто)

Для реализации такого вывода нам необходимо сделать уникальным ключ группировки для каждой физической строки. Рассмотрим, как это сделать по шагам.

Решение 1. Добавление уникального идентификатора строки (Ид) в исходную ТЗ

Самый надежный и контролируемый способ — добавить в исходную таблицу значений дополнительное служебное поле числового типа, которое будет выступать внутренним индексом (итератором) внутри каждой группы данных. Этот индекс должен увеличиваться на единицу только тогда, когда для одной и той же "Хреновины" и одного и того же "Параметра" добавляется еще одно значение.

Посмотрим на пример кода, который решает эту задачу при заполнении таблицы значений:


// Создаем структуру таблицы значений с техническим полем "Ид"
Тз = Новый ТаблицаЗначений;
Тз.Колонки.Добавить("Строки", Новый ОписаниеТипов("Строка"));
Тз.Колонки.Добавить("Колонки", Новый ОписаниеТипов("Строка"));
Тз.Колонки.Добавить("Значение", Новый ОписаниеТипов("Число"));
Тз.Колонки.Добавить("Ид", Новый ОписаниеТипов("Число")); // Наш итератор

// Заполняем данные для Хреновины1
СтрокаТаблицы = Тз.Добавить();
СтрокаТаблицы.Строки = "Хреновина1";
СтрокаТаблицы.Колонки = "Парам1";
СтрокаТаблицы.Значение = 12;
СтрокаТаблицы.Ид = 1; // Первый экземпляр Парам1

СтрокаТаблицы = Тз.Добавить();
СтрокаТаблицы.Строки = "Хреновина1";
СтрокаТаблицы.Колонки = "Парам1";
СтрокаТаблицы.Значение = 13;
СтрокаТаблицы.Ид = 2; // Второй экземпляр Парам1, увеличиваем Ид

СтрокаТаблицы = Тз.Добавить();
СтрокаТаблицы.Строки = "Хреновина1";
СтрокаТаблицы.Колонки = "Парам2";
СтрокаТаблицы.Значение = 17;
СтрокаТаблицы.Ид = 1; // Первый экземпляр Парам2, он встанет в строку с Ид=1

Обратите внимание на распределение поля Ид. Для первой записи "Парам1" мы установили Ид = 1. Для единственной записи "Парам2" мы также установили Ид = 1. Это позволит СКД объединить их на одной строке. А вторая запись "Парам1" получила Ид = 2, что заставит систему вывести ее на отдельной строке.

Если данные заполняются динамически из какого-то другого источника, мы можем автоматизировать этот процесс с помощью простого алгоритма на базе соответствия:


// Алгоритм автоматической нумерации строк в ТЗ
СоответствиеИндексов = Новый Соответствие; // Ключ: Строка + Колонка

Для Каждого СтрокаДанных Из ИсходныйИсточникДанных Цикл
    КлючСвязи = СтрокаДанных.Строки + "_" + СтрокаДанных.Колонки;
    ТекущийИндекс = СоответствиеИндексов.Получить(КлючСвязи);
    
    Если ТекущийИндекс = Неопределено Тогда
        ТекущийИндекс = 1;
    Иначе
        ТекущийИндекс = ТекущийИндекс + 1;
    КонецЕсли;
    
    СоответствиеИндексов.Вставить(КлючСвязи, ТекущийИндекс);
    
    НоваяСтрока = Тз.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаДанных);
    НоваяСтрока.Ид = ТекущийИндекс;
КонецЦикла;

Теперь наша таблица значений полностью готова к передаче во внешний набор данных СКД. Перейдем к настройкам компоновки данных.

Решение 2. Настройка структуры СКД и скрытие служебного поля Ид

После того как мы передали таблицу значений в СКД, нам необходимо правильно настроить структуру кросс-таблицы в настройках отчета. Если мы просто добавим группировку по Ид в строки, пользователи увидят в отчете лишнюю колонку со служебными числами (1, 2 и т.д.), что сильно ухудшит визуальное восприятие отчета. Давайте разберем по шагам, как настроить структуру и изящно скрыть техническое поле.

Выполним следующие действия в конструкторе настроек СКД:

  1. В окне «Настройки» добавим элемент структуры Таблица.
  2. В раздел Строки таблицы добавим группировку по полю Строки.
  3. Внутрь группировки Строки добавим подчиненную группировку по полю Ид. Таким образом, у нас получится иерархия строк: Строки -> Ид.
  4. В раздел Колонки таблицы добавим группировку по полю Колонки.
  5. Вкладку Ресурсы настроим стандартным образом — добавим поле Значение с функцией Сумма(Значение).

Теперь применим трюк для полного визуального скрытия колонки Ид из результирующего отчета:

  1. Выделим подчиненную группировку Ид в структуре строк нашей таблицы.
  2. Перейдем на вкладку «Выбранные поля» этой группировки.
  3. Снимем флаг «Использовать автополе», чтобы очистить список отображаемых полей. Окно выбранных полей для этой группировки должно остаться абсолютно пустым.
  4. Перейдем на вкладку «Сортировка» этой же группировки и добавим туда поле Ид, чтобы строки выводились последовательно (сначала первая строка, потом вторая).

Благодаря этому приему СКД выполнит группировку данных по полю Ид (что физически разделит строки на экране), но сама колонка с цифрами 1 и 2 не будет выведена в финальную таблицу. Мы получим красивый и чистый отчет, где для одной "Хреновины" выводится ровно столько строк, сколько максимальных повторений параметров у нее есть.

Решение 3. Использование функции АвтономерЗаписи() (альтернативный вариант)

Иногда у разработчика нет возможности менять код формирования исходной таблицы значений (например, если это типовой функционал или внешняя подсистема). В этом случае мы можем попытаться сгенерировать уникальные идентификаторы непосредственно внутри СКД.

Для этого мы можем использовать вкладку «Вычисляемые поля»:

  1. Добавим новое вычисляемое поле с именем ИндексСтроки.
  2. В колонке «Выражение» укажем стандартную функцию СКД АвтономерЗаписи().
  3. Добавим это поле в группировку строк таблицы вместо поля Ид.

Важное предупреждение: этот метод имеет существенное ограничение. Функция АвтономерЗаписи() генерирует сквозной номер для абсолютно каждой детальной записи во всем наборе данных. Это означает, что если первая запись "Парам1" получит индекс 1, то запись "Парам2" может получить индекс 3. В результате они не объединятся на одной строке кросс-таблицы, а выведутся лесенкой (по диагонали). Поэтому данный метод подходит только в том случае, если вам не нужно выравнивать разные параметры по одной строке.

Решение 4. Как убрать лишние имена ресурсов из шапки кросс-таблицы

После успешного разделения строк вы можете заметить еще одну эстетическую проблему: СКД автоматически создает дополнительную строку в шапке колонок, где дублирует название ресурса (например, слово "Значение" под каждым параметром). Если у нас всего один ресурс, эта строка избыточна.

Рассмотрим два надежных метода борьбы с этой особенностью:

  1. Трюк с пустым представлением: Перейдем на вкладку «Ресурсы» в схеме компоновки. В свойствах поля ресурса Значение найдем колонку «Заголовок» и введем туда обычный пробел (один символ пробела в кавычках). Строка с названием ресурса в отчете останется, но она визуально станет пустой. Чтобы полностью избавиться от ее высоты, можно в условном оформлении задать минимальную высоту этой строки в значение 0.
  2. Использование макета группировки колонок: Это наиболее профессиональный подход. Мы можем перейти на вкладку «Макеты», нажать кнопку «Добавить макет группировки» и выбрать группировку Колонки с типом «Заголовок». Нарисовав простую ячейку с параметром, содержащим имя колонки, мы заставим СКД использовать наш макет для вывода шапки, полностью игнорируя стандартный вывод имени ресурса.

Мы подробно проанализировали проблему дублирования строк в кросс-таблицах и разобрали эффективные методы ее решения. Использование служебного поля-итератора в сочетании с правильной настройкой видимости полей в структуре СКД позволяет создавать сложные, гибкие и профессиональные отчеты в 1С.

← На главную