Как вывести данные из запроса в одну строку через запятую?

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

При разработке печатных форм в среде 1С программисты часто сталкиваются с задачей, когда список полученных из базы данных записей необходимо вывести не в виде классической вертикальной таблицы, а одной сплошной строкой через запятую. Например, при формировании приказа на командировку или отпуск нескольких сотрудников нам нужно получить красивый текст вида: «Направить в командировку сотрудников: Иванов И.И., Петров П.П., Сидоров С.С.».

В этой статье мы подробно разберем, почему у начинающих разработчиков часто возникает проблема "вывода только первой строки", проанализируем ошибки в коде и рассмотрим несколько эффективных способов решения этой задачи для разных версий платформы 1С:Предприятие.

Выясняем причину: почему код автора не работал?

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


Пока выборка.Следующий() Цикл
    ОбластьДанные.Параметры.Начисление = " приходится на выходные дни " + " " + Формат (Выборка.Начисление, "ДФ=dd.MM.yyyy");
    ОбластьДанные.Параметры.Сотрудник = "В связи с тем, что командировка "+ " " +  Выборка.Сотрудник;
    
    ТабДок.Вывести(ОбластьДанные);
КонецЦикла;

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

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

Важное техническое ограничение: В отличие от классических СУБД (например, MS SQL Server, PostgreSQL или MySQL), в языке запросов 1С отсутствуют встроенные функции агрегации строк вроде STRING_AGG или GROUP_CONCAT. Мы не можем объединить строки из разных записей таблицы непосредственно внутри самого текста запроса. Эту задачу необходимо решать на уровне встроенного языка 1С после выполнения запроса.

Давайте разберем по шагам правильные и современные способы реализации этой задачи.

Способ 1. Использование массива и функции СтрСоединить() (Рекомендуемый для 1С 8.3)

Если вы работаете на современной платформе 1С:Предприятие 8.3 (начиная с версии 8.3.6), самым быстрым, лаконичным и производительным способом является использование встроенной функции СтрСоединить(). Этот метод позволяет мгновенно объединить все элементы одномерного массива в одну текстовую строку с использованием указанного разделителя.

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


// 1. Инициализируем массив для накопления строковых представлений
МассивСотрудников = Новый Массив;

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

// 3. Объединяем все элементы массива в одну большую строку через запятую
СтрокаРезультат = СтрСоединить(МассивСотрудников, ", ");

// 4. Заполняем параметры области макета ОДИН раз вне цикла
ОбластьДанные.Параметры.НомерДок = "в соответствии с приказом № " + СсылкаНаОбъект.Номер;
ОбластьДанные.Параметры.ДатаДок  = " от " + Формат(СсылкаНаОбъект.Дата, "ДФ=dd.MM.yyyy") + "г.";

// Предположим, мы подготовили в макете один общий параметр ТекстСотрудников
ОбластьДанные.Параметры.ТекстСотрудников = "Командировка сотрудников: " + СтрокаРезультат + " приходится на выходные дни.";

// 5. Выводим сформированную область в табличный документ ОДИН раз
ТабДок.Вывести(ОбластьДанные);

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

Способ 2. Накопление строки в цикле (Совместимость с 1С 8.2 и ниже)

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

Проанализируем пример кода для реализации этого метода:


СтрокаРезультат = "";

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

// Заполняем параметр макета полученной строкой
ОбластьДанные.Параметры.ТекстСотрудников = "Сотрудники: " + СтрокаРезультат;
ТабДок.Вывести(ОбластьДанные);

Также для сокращения кода проверку на заполненность первой строки можно лаконично записать с помощью тернарного оператора ?():


СтрокаРезультат = "";
Пока Выборка.Следующий() Цикл
    ТекущиеДанные = Строка(Выборка.Сотрудник) + " (" + Формат(Выборка.Начисление, "ДФ=dd.MM.yyyy") + ")";
    СтрокаРезультат = СтрокаРезультат + ?(ЗначениеЗаполнено(СтрокаРезультат), ", ", "") + ТекущиеДанные;
КонецЦикла;

Способ 3. Использование метода ВыгрузитьКолонку()

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

Рассмотрим, как быстро получить массив значений напрямую из результата запроса:


// 1. Выгружаем результат запроса в Таблицу Значений
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();

// 2. Получаем одномерный массив значений из конкретной колонки таблицы
МассивСотрудников = ТаблицаРезультата.ВыгрузитьКолонку("Сотрудник");

// 3. Объединяем массив в строку
СтрокаСотрудников = СтрСоединить(МассивСотрудников, ", ");

// 4. Передаем в макет
ОбластьДанные.Параметры.СписокСотрудников = СтрокаСотрудников;
ТабДок.Вывести(ОбластьДанные);

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

Способ 4. Агрегация строк в Системе Компоновки Данных (СКД)

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

Для этого в СКД предусмотрена специальная агрегатная функция СоединитьСтроки(). Рассмотрим порядок действий:

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

Важнейший этап: правильная настройка макета печатной формы

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

Чтобы избежать подобных проблем визуализации, выполните следующие настройки в макете вашего документа:

  1. Откройте макет печатной формы (файл с расширением .mxl).
  2. Найдите ячейку, в которую выводится параметр (например, ТекстСотрудников). Поскольку строка может быть очень длинной, рекомендуется **объединить несколько ячеек по горизонтали**, создав широкую область для вывода текста.
  3. Выделите эту объединенную ячейку и откройте её свойства (нажмите клавишу F4 или выберите пункт «Свойства» в контекстном меню).
  4. Найдите свойство «Размещение текста» (в англоязычной версии платформы — Text placement).
  5. По умолчанию там установлено значение Авто или Забивать. Измените его на значение «Переносить» (Wrap).

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

← На главную