Как в СКД вывести различные значения группы горизонтально в виде колонок?

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

При разработке отчетов на базе Системы компоновки данных (СКД) часто возникает классическая задача: как вывести данные с типом связи «один ко многим» не в виде списка строк, а в виде нескольких горизонтальных колонок. Типичный пример — справочник Номенклатура и связанный с ним регистр сведений Штрихкоды. Если у одной позиции товара есть несколько штрихкодов, стандартный отчет выведет по одной строке на каждый штрихкод, что дублирует информацию о номенклатуре и делает отчет трудночитаемым.

В этой статье мы подробно разберем несколько способов решения этой задачи: от программного формирования таблицы значений до «чистого» решения на уровне запроса СКД. Мы проанализируем ситуацию, когда пользователю нужно видеть, например, до 10 штрихкодов в ряд напротив каждого товара.

Способ 1: Использование набора данных - объекта (программный метод)

Этот метод считается наиболее гибким, когда логика распределения данных по колонкам слишком сложна для языка запросов. Суть метода заключается в том, чтобы сначала получить данные обычным запросом, программно обработать их, «развернув» строки в колонки, и передать готовую таблицу значений в СКД.

Рассмотрим по шагам, как это реализовать. Сначала подготовим функцию, которая сформирует таблицу с динамическим количеством колонок Штрихкод1, Штрихкод2 и так далее.


Функция ПолучитьТаблицуШтрихкодов()
    
    Запрос = Новый Запрос("ВЫБРАТЬ
                          |    СпрНоменклатура.Ссылка КАК Номенклатура,
                          |    СпрНоменклатура.Артикул КАК Артикул,
                          |    СпрНоменклатура.Код КАК Код,
                          |    ШтрихкодыНоменклатуры.Штрихкод КАК Штрихкод
                          |ИЗ
                          |    РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыНоменклатуры
                          |        ПОЛНОЕ СОЕДИНЕНИЕ Справочник.Номенклатура КАК СпрНоменклатура
                          |        ПО ШтрихкодыНоменклатуры.Номенклатура = СпрНоменклатура.Ссылка");
    
    Результат = Запрос.Выполнить().Выгрузить();
    
    ТаблицаШтрихкоды = Новый ТаблицаЗначений;
    ТаблицаШтрихкоды.Колонки.Добавить("Номенклатура");
    ТаблицаШтрихкоды.Колонки.Добавить("Артикул");
    ТаблицаШтрихкоды.Колонки.Добавить("Код");
    ТаблицаШтрихкоды.Колонки.Добавить("Штрихкод1");
    
    Для Каждого СтрокаРезультата Из Результат Цикл
        
        НайденнаяСтрокаТаблицы = ТаблицаШтрихкоды.Найти(СтрокаРезультата.Номенклатура, "Номенклатура");
        
        Если НайденнаяСтрокаТаблицы = Неопределено Тогда
            
            НоваяСтрока = ТаблицаШтрихкоды.Добавить();
            НоваяСтрока.Номенклатура = СтрокаРезультата.Номенклатура;
            НоваяСтрока.Артикул = СтрокаРезультата.Артикул;
            НоваяСтрока.Код = СтрокаРезультата.Код;
            НоваяСтрока.Штрихкод1 = СтрокаРезультата.Штрихкод;
            
        Иначе
            
            Сч = 2;
            ШтрихкодЗаписан = Ложь; 
            
            Пока НЕ ШтрихкодЗаписан Цикл
                
                ИмяКолонки = "Штрихкод" + Сч;
                Если ТаблицаШтрихкоды.Колонки.Найти(ИмяКолонки) = Неопределено Тогда
                    ТаблицаШтрихкоды.Колонки.Добавить(ИмяКолонки);
                КонецЕсли;
                
                Если Строка(НайденнаяСтрокаТаблицы[ИмяКолонки]) = "" Тогда
                    НайденнаяСтрокаТаблицы[ИмяКолонки] = СтрокаРезультата.Штрихкод;
                    ШтрихкодЗаписан = Истина;
                КонецЕсли;
                
                Сч = Сч + 1;
                
            КонецЦикла;
        КонецЕсли;
        
    КонецЦикла;
    
    Возврат ТаблицаШтрихкоды;
    
КонецФункции

После подготовки таблицы её необходимо передать в СКД. Для этого в схеме компоновки данных мы создаем Набор данных - объект с именем ТаблицаШтрихкодов и прописываем в нем все ожидаемые поля. В модуле отчета, в процедуре ПриКомпоновкеРезультата, передаем нашу таблицу в ПроцессорКомпоновкиДанных.

Преимущества этого метода: мы полностью контролируем процесс заполнения ячеек и можем ограничить количество колонок или добавить любую дополнительную логику проверки. Недостатки: потеря производительности на больших объемах данных и необходимость вручную прописывать поля в схеме СКД.

Способ 2: Нумерация строк в запросе и группировка колонок в СКД

Разберем более «изящное» решение, которое позволяет обойтись без написания кода на языке 1С и выполнить всю работу средствами SQL-запроса и настроек структуры СКД. Основная проблема при использовании стандартной группировки по полю Штрихкод в колонках заключается в том, что СКД создаст отдельный столбец для каждого уникального значения штрихкода в системе. Нам же нужно, чтобы колонки назывались «Штрихкод 1», «Штрихкод 2» и так далее.

Для этого нам нужно присвоить каждому штрихкоду порядковый номер внутри группы номенклатуры. Проанализируем, как это сделать в запросе:

  1. Создаем временную таблицу со штрихкодами.
  2. Соединяем эту таблицу саму с собой по полю Номенклатура.
  3. В условии соединения указываем, что штрихкод из первой таблицы должен быть больше штрихкода из второй: Т1.Штрихкод >= Т2.Штрихкод.
  4. Группируем результат по Т1.Номенклатура и Т1.Штрихкод, а в поле выбора считаем Количество(Т2.Штрихкод).

Полученное число и будет порядковым номером (индексом) колонки. Посмотрим на пример такого запроса:


ВЫБРАТЬ
    Штрихкоды.Номенклатура КАК Номенклатура,
    Штрихкоды.Штрихкод КАК Штрихкод,
    КОЛИЧЕСТВО(ШтрихкодыАналоги.Штрихкод) КАК ПорядковыйНомер
ИЗ
    РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
        ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыАналоги
        ПО Штрихкоды.Номенклатура = ШтрихкодыАналоги.Номенклатура
            И Штрихкоды.Штрихкод >= ШтрихкодыАналоги.Штрихкод
СГРУППИРОВАТЬ ПО
    Штрихкоды.Номенклатура,
    Штрихкоды.Штрихкод

Теперь выясним, как настроить отчет в СКД:

В итоге СКД автоматически сформирует колонки «1», «2», «3»... до максимального количества штрихкодов, встреченных у одной номенклатуры. Чтобы заголовки выглядели красиво, можно использовать Выражение представления для поля ПорядковыйНомер, например: "Штрихкод " + Формат(ПорядковыйНомер, "ЧГ=0").

Способ 3: Использование функции Массив() в ресурсах

Если версия платформы 1С позволяет использовать агрегатную функцию Массив() в ресурсах СКД, мы можем применить еще один интересный подход. Рассмотрим ситуацию, когда мы не хотим использовать сложные соединения в запросе.

Проанализируем шаги реализации:

  1. Добавляем поле Штрихкод в Ресурсы. В поле выражения пишем: Массив(Штрихкод).
  2. Создаем Вычисляемые поля: Штрихкод_1, Штрихкод_2... Штрихкод_10.
  3. В выражении каждого вычисляемого поля вызываем функцию общего модуля, которая вернет элемент массива по индексу. Например: ПолучитьИзМассива(ВычислитьВыражение("Массив(Штрихкод)", "Номенклатура"), 0).

Этот метод позволяет сохранить структуру отчета в виде списка, а не таблицы, что иногда удобнее для дальнейшей выгрузки в Excel. Однако он требует наличия экспортируемой функции в общем модуле для безопасной работы с индексами массива (чтобы избежать ошибки «Индекс за пределами диапазона»).

Резюме и рекомендации

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

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

Третий способ (через агрегатные функции) удобен для быстрого решения задачи «в лоб», если количество колонок строго ограничено и невелико. Выбирайте метод исходя из ваших задач и объема данных в базе.

← На главную