Как объединить несколько строк в одну и развернуть данные в разные колонки в 1С

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

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

Способ 1. Использование агрегатных функций в запросе (Метод «Максимум + Выбор»)

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

Разберем пример построения такого запроса:


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

Преимущества метода:

  1. Выполняется за один проход по таблице базы данных.
  2. Не создает вложенных соединений, которые могут замедлить работу при больших объемах данных.
  3. Легко масштабируется, если типов инструкций станет три или четыре.

Способ 2. Левое соединение таблицы самой с собой

Если данные не имеют четкого признака категории, но мы точно знаем, что строк всегда две, можно использовать механизм соединений. Рассмотрим ситуацию, когда нам нужно получить данные из одной и той же таблицы, но «приклеить» вторую строку к первой по ключу (в нашем случае — по полю Вагон).

Выясним, как составить такой запрос по шагам:

  1. Сначала выберем все уникальные ключи (вагоны).
  2. Присоединим к ним первую запись (например, с минимальным наименованием инструкции).
  3. Присоединим вторую запись (с наименованием инструкции, которое больше первого).

ВЫБРАТЬ
    Т1.Вагон,
    Т1.Инструкция КАК Инструкция1,
    Т2.Инструкция КАК Инструкция2,
    Т1.ОбщееПоле
ИЗ
    РегистрСведений.Инструкции КАК Т1
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.Инструкции КАК Т2
        ПО Т1.Вагон = Т2.Вагон
            И Т1.Инструкция < Т2.Инструкция
ГДЕ
    // Здесь можно добавить фильтры для исключения лишних дублей

Этот способ часто называют «костыльным», так как он требует сложной логики условий в соединении (использование знака < или > для строк), чтобы не получить кросс-произведение всех строк. Тем не менее, для двух записей он вполне работоспособен.

Способ 3. Агрегатная функция «СоединитьСтроки» в СКД

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

Проанализируем алгоритм настройки отчета в СКД:

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

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

Способ 4. Программный обход выборки с заполнением параметров

Бывают случаи, когда логика настолько сложна, что проще обработать результат запроса кодом на языке 1С. Рассмотрим решение, которое предложил автор темы. Суть заключается в том, чтобы при переборе результата запроса не выводить сразу новую строку в документ, а проверять условия и заполнять соответствующие параметры макета.

Посмотрим на пример реализации такого алгоритма:


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

Важное примечание: Если вы используете поиск внутри цикла (например, НайтиСледующий), будьте осторожны с производительностью. При большом количестве вагонов такой отчет может формироваться очень долго. Профессиональнее будет сначала выгрузить данные в ТаблицаЗначений.

Способ 5. Метод «Свернуть» для Таблицы Значений

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

Разберем по шагам, как подготовить таблицу:

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

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

Для Каждого СтрокаТЗ Из ТЗДанные Цикл
    Если СтрокаТЗ.Отдел = "Вагонный" Тогда
        СтрокаТЗ.Инструкция1 = СтрокаТЗ.Инструкция;
    Иначе
        СтрокаТЗ.Инструкция2 = СтрокаТЗ.Инструкция;
    КонецЕсли;
КонецЦикла;

// Сворачиваем таблицу по всем полям, кроме исходной инструкции
ТЗДанные.Свернуть("Вагон, ОстальныеПоля", "Инструкция1, Инструкция2");

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

Резюме

Мы проанализировали пять различных подходов к решению задачи объединения строк. Для простых отчетов идеальным выбором будет СКД с функцией СоединитьСтроки или кросс-таблица. Если данные нужны для программной обработки, лучше всего использовать запрос с агрегатной функцией МАКСИМУМ и условием ВЫБОР. Это гарантирует высокую скорость работы и надежность кода.

← На главную