Как объединить несколько характеристик или значений в одну строку для отображения в динамическом списке 1С?

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

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

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

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

Поэтому, если мы попытаемся использовать СоединитьСтроки() прямо в запросе динамического списка, мы, скорее всего, столкнемся с ошибками или некорректным поведением. Рассмотрим подробнее, какие есть рабочие решения.

Решение 1: Предварительный расчет и сохранение объединенной строки (рекомендуемый подход)

Это самый производительный и рекомендуемый подход. Если нам нужно постоянно отображать объединенную строку характеристик, лучше всего предварительно рассчитать ее и сохранить в отдельном строковом реквизите основного объекта. Мы можем увидеть аналогичный подход в типовых конфигурациях, например, в 1С:ЗУП, где для ведомостей используется реквизит СоставВедомости.

  1. Создаем новый реквизит: Добавим к нашему справочнику "Машинки" новый реквизит типа Строка (например, с неограниченной длиной), назовем его ПредставлениеХарактеристик.

  2. Реализуем логику обновления: При изменении любых характеристик машинки (добавлении, изменении, удалении) нам необходимо обновлять значение этого строкового реквизита. Это можно сделать в различных местах:

    • В обработчике события при записи объекта: Например, в событии ПриЗаписи() или ОбработкаЗаполнения() для справочника "Машинки" или для подчиненного справочника/регистра, который хранит характеристики.

      
      // Пример кода в модуле объекта справочника "Машинки"
      Процедура ПриЗаписи(Отказ)
          // Вызываем функцию, которая соберет все характеристики в строку
          ЭтотОбъект.ПредставлениеХарактеристик = СформироватьСтрокуХарактеристик(ЭтотОбъект.Ссылка);
      КонецПроцедуры
      
      // Отдельная функция для формирования строки характеристик
      Функция СформироватьСтрокуХарактеристик(СсылкаНаОбъект)
          Запрос = Новый Запрос;
          Запрос.Текст = 
              "ВЫБРАТЬ
              |    ДопХарактеристики.Наименование КАК Характеристика
              |ИЗ
              |    Справочник.Машинки.ДопХарактеристики КАК ДопХарактеристики
              |ГДЕ
              |    ДопХарактеристики.Ссылка = &СсылкаНаОбъект
              |УПОРЯДОЧИТЬ ПО
              |    Характеристика";
          Запрос.УстановитьПараметр("СсылкаНаОбъект", СсылкаНаОбъект);
                          
          РезультатЗапроса = Запрос.Выполнить().Выгрузить();
                          
          МассивСтрок = Новый Массив;
          Для Каждого СтрокаТЧ Из РезультатЗапроса Цикл
              МассивСтрок.Добавить(СтрокаТЧ.Характеристика);
          КонецЦикла;
                          
          Возврат СтрСоединить(МассивСтрок, ", ");
      КонецФункции
      
    • В обработчиках форм: Если характеристики редактируются в отдельных формах, можно инициировать обновление в этих формах при записи изменений.

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

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

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

Решение 2: Использование множественных ЛЕВЫХ СОЕДИНЕНИЙ для фиксированного числа характеристик

Этот подход может быть применен, если количество характеристик невелико и строго фиксировано. Мы можем использовать несколько ЛЕВЫХ СОЕДИНЕНИЙ (LEFT JOIN) в запросе динамического списка для вывода каждой характеристики в отдельную колонку, а затем объединить их в вычисляемом поле.

  1. Формируем запрос с соединениями: Для каждой характеристики, которую мы хотим вывести, мы делаем отдельное ЛЕВОЕ СОЕДИНЕНИЕ с таблицей характеристик.

    
    ВЫБРАТЬ 
        Машинки.Ссылка КАК Ссылка, 
        Машинки.Наименование КАК Наименование, 
        ДопХарактеристики1.Реквизит1 КАК Характеристика1, 
        ДопХарактеристики2.Реквизит1 КАК Характеристика2,
        ДопХарактеристики3.Реквизит1 КАК Характеристика3
    ИЗ 
        Справочник.Машинки КАК Машинки 
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Машинки.ДопХарактеристики КАК ДопХарактеристики1 
        ПО ДопХарактеристики1.Ссылка = Машинки.Ссылка И ДопХарактеристики1.НомерСтроки = 1 
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Машинки.ДопХарактеристики КАК ДопХарактеристики2 
        ПО ДопХарактеристики2.Ссылка = Машинки.Ссылка И ДопХарактеристики2.НомерСтроки = 2
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Машинки.ДопХарактеристики КАК ДопХарактеристики3 
        ПО ДопХарактеристики3.Ссылка = Машинки.Ссылка И ДопХарактеристики3.НомерСтроки = 3
    

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

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

    
    ВЫБРАТЬ 
        Машинки.Ссылка КАК Ссылка, 
        Машинки.Наименование КАК Наименование, 
        ЕСТЬNULL(ДопХарактеристики1.Реквизит1, "") + ", " + 
        ЕСТЬNULL(ДопХарактеристики2.Реквизит1, "") + ", " + 
        ЕСТЬNULL(ДопХарактеристики3.Реквизит1, "") КАК ПредставлениеХарактеристик
    ИЗ 
        Справочник.Машинки КАК Машинки 
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Машинки.ДопХарактеристики КАК ДопХарактеристики1 
        ПО ДопХарактеристики1.Ссылка = Машинки.Ссылка И ДопХарактеристики1.НомерСтроки = 1 
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Машинки.ДопХарактеристики КАК ДопХарактеристики2 
        ПО ДопХарактеристики2.Ссылка = Машинки.Ссылка И ДопХарактеристики2.НомерСтроки = 2
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Машинки.ДопХарактеристики КАК ДопХарактеристики3 
        ПО ДопХарактеристики3.Ссылка = Машинки.Ссылка И ДопХарактеристики3.НомерСтроки = 3
    

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

Ограничения этого подхода:

Мы рекомендуем использовать этот подход только при очень небольшом и строго фиксированном количестве характеристик (не более 2-3).

Решение 3: Программное формирование строки в событии управляемой формы

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

  1. Добавляем дополнительную колонку: В динамический список на форме мы добавляем новую колонку, которая не привязана к данным запроса (т.е. у нее нет поля ПутьКДанным).

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

    
    // Пример кода в модуле формы
    Процедура СписокПриПолученииДанных(Элемент, Данные, Отказ)
        // Данные - это таблица значений, содержащая текущую порцию данных динамического списка.
        // Мы можем обойти эти данные и добавить значения в нашу "виртуальную" колонку.
    
        Для Каждого СтрокаДанных Из Данные Цикл
            // Здесь мы должны получить характеристики для текущей строки
            // и сформировать объединенную строку.
            // Например, если у нас есть ссылка на объект в колонке "Ссылка":
            СсылкаНаМашинку = СтрокаДанных.Ссылка;
                    
            // Вызываем функцию для формирования строки характеристик
            // (аналогичную той, что мы использовали в Решении 1)
            СтрокаДанных.ПредставлениеХарактеристик = СформироватьСтрокуХарактеристик(СсылкаНаМашинку); 
                    
            // Если колонка называется "ВиртуальнаяКолонка", то:
            // СтрокаДанных.ВиртуальнаяКолонка = СформироватьСтрокуХарактеристик(СсылкаНаМашинку);
        КонецЦикла;
    КонецПроцедуры
    
    // Функция СформироватьСтрокуХарактеристик должна быть доступна из модуля формы,
    // например, как экспортная функция модуля менеджера справочника или общая функция.
    

Ограничения этого подхода:

Этот метод подходит для случаев, когда производительность не критична (малое количество данных) и нет необходимости в поиске/сортировке по этой колонке.

Важные моменты: Производительность динамических списков

Мы проанализировали несколько подходов, и каждый из них имеет свои особенности, особенно в части производительности. Давайте еще раз подчеркнем основные факторы, влияющие на скорость работы динамических списков:

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

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

← К списку