Как транспонировать строки в колонки в запросе 1С

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

В практике разработки на платформе 1С часто возникает задача преобразования данных из вертикального вида (строки) в горизонтальный (колонки). Типичный пример — вывод характеристик номенклатуры, дополнительных сведений или результатов замеров, где каждое новое свойство хранится в отдельной строке, а в отчете их нужно выстроить в ряд для каждого объекта. Рассмотрим подробнее, как решить эту задачу различными методами, проанализируем их эффективность и разберем конкретные примеры кода.

Метод 1: Группировка и агрегатные функции (Золотой стандарт)

Этот метод считается наиболее оптимальным с точки зрения производительности SQL-сервера. Суть заключается в том, что мы выбираем все данные одним списком, а затем «разбрасываем» их по колонкам с помощью конструкции ВЫБОР, используя группировку по ключевому полю. Рассмотрим этот подход на примере получения значений П1, П2 и П3 для объекта К1.

Проанализируем пример запроса:


ВЫБРАТЬ
    ТаблицаДанных.Объект КАК Объект,
    МАКСИМУМ(ВЫБОР
            КОГДА ТаблицаДанных.Свойство = "П1"
                ТОГДА ТаблицаДанных.Значение
            ИНАЧЕ NULL
        КОНЕЦ) КАК ПолеП1,
    МАКСИМУМ(ВЫБОР
            КОГДА ТаблицаДанных.Свойство = "П2"
                ТОГДА ТаблицаДанных.Значение
            ИНАЧЕ NULL
        КОНЕЦ) КАК ПолеП2,
    МАКСИМУМ(ВЫБОР
            КОГДА ТаблицаДанных.Свойство = "П3"
                ТОГДА ТаблицаДанных.Значение
            ИНАЧЕ NULL
        КОНЕЦ) КАК ПолеП3
ИЗ
    ВременнаяТаблицаДанных КАК ТаблицаДанных
СГРУППИРОВАТЬ ПО
    ТаблицаДанных.Объект

Почему это работает: функция МАКСИМУМ (или МИНИМУМ) игнорирует значения NULL. В результате для каждой группы по объекту в конкретную колонку попадет только то значение, которое соответствует условию ВЫБОР, а все остальные строки превратятся в NULL и будут отброшены агрегатной функцией.

Этот способ требует всего одного сканирования таблицы, что делает его предпочтительным при работе с большими объемами данных.

Метод 2: Использование множественных левых соединений

Если количество колонок заранее известно и оно невелико (например, не более 5-10), можно использовать последовательное соединение таблиц. Рассмотрим ситуацию, когда нам нужно собрать данные из разных источников или по разным фильтрам в одну строку.

Разберем пример кода:


ВЫБРАТЬ
    ВТ_Объекты.Ссылка КАК Объект,
    ЕСТЬNULL(ВТ_Данные1.Значение, 0) КАК Значение1,
    ЕСТЬNULL(ВТ_Данные2.Значение, 0) КАК Значение2
ИЗ
    ВТ_Объекты КАК ВТ_Объекты
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные1 КАК ВТ_Данные1
        ПО ВТ_Объекты.Ссылка = ВТ_Данные1.Объект
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_Данные2 КАК ВТ_Данные2
        ПО ВТ_Объекты.Ссылка = ВТ_Данные2.Объект

Важные нюансы при использовании соединений:

  1. Производительность: Каждое левое соединение — это отдельное обращение СУБД к данным. Если колонок будет 20, запрос может начать существенно "тормозить".
  2. Индексация: При использовании временных таблиц в соединениях обязательно индексируйте поле связи (в нашем примере — поле Ссылка или Объект). Без этого SQL-сервер будет выполнять ресурсоемкое сканирование всей таблицы для каждого соединения.
  3. Обработка NULL: Всегда используйте функцию ЕСТЬNULL, чтобы избежать пустых значений в итоговом результате, особенно если планируются дальнейшие математические операции.

Метод 3: Использование Системы компоновки данных (СКД)

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

Выполним следующие шаги для настройки:

  1. В схеме компоновки данных создадим простой запрос, который выбирает данные в «плоском» виде: Объект, ИмяСвойства, Значение.
  2. Перейдем на закладку "Настройки".
  3. Добавим в структуру отчета элемент типа "Таблица".
  4. В строки таблицы перетащим поле Объект.
  5. В колонки таблицы перетащим поле ИмяСвойства.
  6. В выбранные поля (ресурсы) добавим поле Значение.

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

Метод 4: Динамическое построение текста запроса

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

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

  1. Сначала выполним вспомогательный запрос, чтобы получить список всех уникальных свойств (будущих колонок).
  2. Циклом по результату этого запроса сформируем фрагменты текста для блока ВЫБРАТЬ.
  3. Соберем итоговый текст запроса и выполним его.

Пример программного формирования кода:


ТекстВыбора = "";
Для Каждого СтрокаСвойство Из ТаблицаСвойств Цикл
    ТекстВыбора = ТекстВыбора + 
        ", МАКСИМУМ(ВЫБОР КОГДА Свойство = &Свойство" + СтрокаСвойство.Номер + 
        " ТОГДА Значение ИНАЧЕ NULL КОНЕЦ) КАК " + СтрокаСвойство.ИмяБезПробелов;
    Запрос.УстановитьПараметр("Свойство" + СтрокаСвойство.Номер, СтрокаСвойство.Ссылка);
КонецЦикла;

Запрос.Текст = "ВЫБРАТЬ Объект" + ТекстВыбора + " ИЗ ВТ_Данные СГРУППИРОВАТЬ ПО Объект";

Важное предостережение: при формировании условий ВЫБОР КОГДА старайтесь сравнивать ссылки (через параметры), а не строковые имена свойств через точку (например, Свойство.Наименование). Прямое обращение к реквизитам через точку в условии запроса (разыменование ссылки) приводит к неявному соединению таблиц на уровне СУБД, что замедляет выполнение в разы.

Сводная таблица методов

Выясним, какой метод лучше использовать в конкретной ситуации:

  1. Группировка с МАКСИМУМ(ВЫБОР...): Универсальный и самый быстрый метод для фиксированного или динамически формируемого набора колонок в коде.
  2. Левые соединения: Допустимы только для очень малого количества стабильных колонок (например, "Фамилия", "Имя", "Отчество").
  3. Механизм таблиц СКД: Лучший выбор для отчетов, так как не требует написания сложного кода и автоматически подстраивается под данные.
  4. Объединение (UNION): Иногда используется для предварительной подготовки данных перед группировкой (как описано в сообщении 22 форума), чтобы "разнести" разные показатели по разным столбцам в рамках одной временной таблицы.

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

← На главную