Как развернуть результат запроса из строк в колонки табличной части?

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

В практике разработки на платформе 1С:Предприятие часто встречается задача, когда результат запроса возвращает данные в «вертикальном» виде (множество строк), а пользователю необходимо представить их в «горизонтальном» (одна строка с множеством колонок). Классический пример — отображение характеристик номенклатуры. В базе данных характеристики хранятся в отдельных записях, но в интерфейсе обработки или документа мы хотим видеть одну строку с товаром и несколько колонок для его свойств: «Характеристика 1», «Характеристика 2» и так далее.

Рассмотрим подробно, как решить эту задачу, имея фиксированную структуру табличной части (например, заранее созданные колонки «Характеристика1», «Характеристика2», «Характеристика3»). Мы разберем несколько методов: от классического обхода группировок до манипуляций с Таблицей Значений.

Постановка задачи

Допустим, у нас есть результат запроса, который выглядит следующим образом:

Нам необходимо загрузить эти данные в табличную часть обработки, которая имеет структуру:

Номенклатура | Характеристика 1 | Характеристика 2 | Характеристика 3

В итоге должно получиться:

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

Это наиболее производительный и правильный с точки зрения архитектуры 1С метод. Суть заключается в том, что мы перекладываем работу по группировке данных на SQL-сервер (или движок файловой базы), используя конструкцию ИТОГИ (вам может пригодиться Шпаргалка по языку запросов). Затем мы используем двойной цикл обхода выборки.

Разберем алгоритм по шагам:

  1. Пишем запрос, который выбирает Номенклатуру и Характеристику. При работе со сложными данными может потребоваться добавление данных в существующую временную таблицу.
  2. Добавляем предложение ИТОГИ ПО Номенклатура. Это позволит нам получать данные порциями: сначала заголовок (Товар), затем детальные записи (Характеристики). Используйте инструменты для быстрого анализа данных, чтобы проверить корректность работы итогов.
  3. При обходе результата используем метод Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам).
  4. Во вложенном цикле заполняем колонки, используя счетчик.

Рассмотрим пример кода:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   ТоварыНаСкладах.Номенклатура КАК Номенклатура,
    |   ТоварыНаСкладах.Характеристика КАК Характеристика
    |ИЗ
    |   РегистрНакопления.ТоварыНаСкладах КАК ТоварыНаСкладах
    |
    |УПОРЯДОЧИТЬ ПО
    |   Номенклатура,
    |   Характеристика
    |ИТОГИ ПО
    |   Номенклатура";

// Получаем результат запроса
Результат = Запрос.Выполнить();

// Начинаем выборку по группировкам (по Номенклатуре)
ВыборкаНоменклатура = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаНоменклатура.Следующий() Цикл
    
    // Для каждой новой номенклатуры создаем новую строку в табличной части
    НоваяСтрока = Объект.МояТабличнаяЧасть.Добавить();
    НоваяСтрока.Номенклатура = ВыборкаНоменклатура.Номенклатура;
    
    // Получаем детальные записи (характеристики) для текущей номенклатуры
    ВыборкаДетали = ВыборкаНоменклатура.Выбрать();
    
    Счетчик = 1; // Сбрасываем счетчик для новой строки
    
    Пока ВыборкаДетали.Следующий() Цикл
        
        // Проверяем, чтобы не выйти за пределы созданных колонок (например, если их всего 3)
        Если Счетчик > 3 Тогда
            Прервать;
        КонецЕсли;
        
        // Формируем имя колонки динамически: "Характеристика" + "1", "2" и т.д.
        ИмяКолонки = "Характеристика" + Строка(Счетчик);
        
        // Записываем значение в колонку
        НоваяСтрока[ИмяКолонки] = ВыборкаДетали.Характеристика;
        
        // Увеличиваем счетчик для следующей характеристики
        Счетчик = Счетчик + 1;
        
    КонецЦикла;
    
КонецЦикла;

Проверить текст запроса и структуру итогов удобнее всего через Консоль запросов УФ 8.3.2.24.22 (мод от Dr.Zombi). Преимущества метода:

Способ 2: Постобработка Таблицы Значений

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

Алгоритм действий:

  1. Выгружаем результат запроса в Таблицу Значений (ТЗ).
  2. Создаем копию этой ТЗ и сворачиваем её по колонке Номенклатура. Так мы получим список уникальных товаров (будущих строк ТЧ).
  3. Обходим свернутую таблицу. Для каждого товара ищем все его характеристики в исходной (полной) таблице.
  4. Заполняем колонки.

Посмотрим на реализацию:


// Допустим, Запрос уже выполнен и выгружен в ТЗ
ТЗ_ВсеДанные = Запрос.Выполнить().Выгрузить();

// Создаем таблицу уникальных номенклатур
ТЗ_Уникальные = ТЗ_ВсеДанные.Скопировать();
ТЗ_Уникальные.Свернуть("Номенклатура"); // Останутся только уникальные товары

Для Каждого СтрУник Из ТЗ_Уникальные Цикл
    
    // Добавляем строку в табличную часть
    НоваяСтрокаТЧ = Объект.МояТабличнаяЧасть.Добавить();
    НоваяСтрокаТЧ.Номенклатура = СтрУник.Номенклатура;
    
    // Ищем все строки с этой номенклатурой в исходной таблице
    Отбор = Новый Структура("Номенклатура", СтрУник.Номенклатура);
    НайденныеСтроки = ТЗ_ВсеДанные.НайтиСтроки(Отбор);
    
    Счетчик = 1;
    
    Для Каждого СтрДетали Из НайденныеСтроки Цикл
        
        Если Счетчик > 3 Тогда
            Прервать;
        КонецЕсли;
        
        НоваяСтрокаТЧ["Характеристика" + Строка(Счетчик)] = СтрДетали.Характеристика;
        Счетчик = Счетчик + 1;
        
    КонецЦикла;
    
КонецЦикла;

Этот метод удобен, если данные уже находятся в памяти в виде ТаблицаЗначений, например, полученные из внешней системы или другого документа.

Способ 3: Агрегация строк (для платформы 8.3.24+)

Если ваша задача — просто вывести список характеристик для информации (в одну ячейку), и вы используете современную платформу версии 8.3.24 и выше, можно воспользоваться новой функцией языка запросов АгрегатСтроки (StringAggregate).

Это не разнесет данные по разным колонкам, но позволит собрать их в одну строку через запятую прямо в запросе, что часто заменяет необходимость создания множества колонок.


ВЫБРАТЬ
    Товары.Номенклатура,
    АгрегатСтроки(Товары.Характеристика, ", ") КАК ВсеХарактеристики
ИЗ
    Справочник.Товары КАК Товары
СГРУППИРОВАТЬ ПО
    Товары.Номенклатура

Результатом будет одна строка: «Размер XL, Цвет Красный». Если же строго требуется разделение по колонкам для дальнейшего редактирования, используйте Способ 1.

Важные нюансы

Ограничение количества колонок. В приведенных примерах мы жестко ограничивали цикл условием Если Счетчик > 3. Это необходимо, так как в метаданных (в Конфигураторе) у вас создано конечное количество реквизитов (Характеристика1, Характеристика2, Характеристика3). Если характеристик будет 4, и вы попытаетесь обратиться к НоваяСтрока["Характеристика4"], платформа выдаст ошибку, так как такого поля не существует.

Динамические колонки. Если вы заранее не знаете, сколько будет характеристик (может быть 3, а может быть 10), то фиксированная табличная часть вам не подойдет. В этом случае необходимо использовать программное создание реквизитов формы. Алгоритм будет сложнее:

  1. Выполнить запрос.
  2. Выяснить максимальное количество характеристик у одного товара.
  3. С помощью метода ИзменитьРеквизиты программно добавить нужное количество колонок в ТаблицаЗначений на форме.
  4. С помощью Элементы.Добавить создать поля ввода для этих колонок в таблице формы.
  5. Заполнить данные по алгоритму из Способа 1.

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

← На главную