При разработке печатных форм в среде 1С программисты часто сталкиваются с задачей, когда список полученных из базы данных записей необходимо вывести не в виде классической вертикальной таблицы, а одной сплошной строкой через запятую. Например, при формировании приказа на командировку или отпуск нескольких сотрудников нам нужно получить красивый текст вида: «Направить в командировку сотрудников: Иванов И.И., Петров П.П., Сидоров С.С.».
В этой статье мы подробно разберем, почему у начинающих разработчиков часто возникает проблема "вывода только первой строки", проанализируем ошибки в коде и рассмотрим несколько эффективных способов решения этой задачи для разных версий платформы 1С:Предприятие.
Для начала давайте детально проанализируем ситуацию, описанную в теме форума. Автор пытается обойти выборку запроса в цикле и вывести данные в область макета. Посмотрим на фрагмент его исходного кода:
Пока выборка.Следующий() Цикл
ОбластьДанные.Параметры.Начисление = " приходится на выходные дни " + " " + Формат (Выборка.Начисление, "ДФ=dd.MM.yyyy");
ОбластьДанные.Параметры.Сотрудник = "В связи с тем, что командировка "+ " " + Выборка.Сотрудник;
ТабДок.Вывести(ОбластьДанные);
КонецЦикла;
В данном подходе кроются сразу две логические ошибки, которые мешают получить желаемый результат:
ОбластьДанные.Параметры.Начисление и ОбластьДанные.Параметры.Сотрудник записываются новые значения текущей строки выборки. Старые значения просто стираются. В итоге к моменту вывода в параметрах всегда будут находиться данные только из самой последней записи выборки.ТабДок.Вывести(ОбластьДанные) вызывается внутри цикла. Это означает, что программа будет добавлять новую строку в табличный документ на каждом шаге цикла. Вместо одной аккуратной строки мы получим вертикальный список дублирующихся областей макета, в каждой из которых будет выведен только один сотрудник.Важное техническое ограничение: В отличие от классических СУБД (например, MS SQL Server, PostgreSQL или MySQL), в языке запросов 1С отсутствуют встроенные функции агрегации строк вроде STRING_AGG или GROUP_CONCAT. Мы не можем объединить строки из разных записей таблицы непосредственно внутри самого текста запроса. Эту задачу необходимо решать на уровне встроенного языка 1С после выполнения запроса.
Давайте разберем по шагам правильные и современные способы реализации этой задачи.
Если вы работаете на современной платформе 1С:Предприятие 8.3 (начиная с версии 8.3.6), самым быстрым, лаконичным и производительным способом является использование встроенной функции СтрСоединить(). Этот метод позволяет мгновенно объединить все элементы одномерного массива в одну текстовую строку с использованием указанного разделителя.
Давайте перепишем алгоритм формирования печатной формы, используя этот подход:
// 1. Инициализируем массив для накопления строковых представлений
МассивСотрудников = Новый Массив;
// 2. Обходим выборку запроса и заполняем массив данными
Пока Выборка.Следующий() Цикл
// Формируем строковое представление для каждого сотрудника и даты
ТекущаяСтрока = Строка(Выборка.Сотрудник) + " (" + Формат(Выборка.Начисление, "ДФ=dd.MM.yyyy") + ")";
// Добавляем полученную строку в массив
МассивСотрудников.Добавить(ТекущаяСтрока);
КонецЦикла;
// 3. Объединяем все элементы массива в одну большую строку через запятую
СтрокаРезультат = СтрСоединить(МассивСотрудников, ", ");
// 4. Заполняем параметры области макета ОДИН раз вне цикла
ОбластьДанные.Параметры.НомерДок = "в соответствии с приказом № " + СсылкаНаОбъект.Номер;
ОбластьДанные.Параметры.ДатаДок = " от " + Формат(СсылкаНаОбъект.Дата, "ДФ=dd.MM.yyyy") + "г.";
// Предположим, мы подготовили в макете один общий параметр ТекстСотрудников
ОбластьДанные.Параметры.ТекстСотрудников = "Командировка сотрудников: " + СтрокаРезультат + " приходится на выходные дни.";
// 5. Выводим сформированную область в табличный документ ОДИН раз
ТабДок.Вывести(ОбластьДанные);
Этот способ крайне эффективен, так как платформа оптимизирует выделение памяти под результирующую строку при работе с массивом, избегая лишних промежуточных операций конкатенации.
Если ваша информационная база работает на старой версии платформы или запущена в режиме совместимости с версиями ниже 8.3.6, функция СтрСоединить() будет недоступна. В таком случае мы можем применить классический метод последовательного сложения строк (конкатенации) непосредственно внутри цикла обхода выборки.
Проанализируем пример кода для реализации этого метода:
СтрокаРезультат = "";
Пока Выборка.Следующий() Цикл
// Формируем строковое представление текущей записи
ТекущиеДанные = Строка(Выборка.Сотрудник) + " (" + Формат(Выборка.Начисление, "ДФ=dd.MM.yyyy") + ")";
// Проверяем, заполнена ли уже строка результатов.
// Если заполнена, то добавляем запятую перед добавлением нового сотрудника.
Если ЗначениеЗаполнено(СтрокаРезультат) Тогда
СтрокаРезультат = СтрокаРезультат + ", " + ТекущиеДанные;
Иначе
СтрокаРезультат = ТекущиеДанные;
КонецЕсли;
КонецЦикла;
// Заполняем параметр макета полученной строкой
ОбластьДанные.Параметры.ТекстСотрудников = "Сотрудники: " + СтрокаРезультат;
ТабДок.Вывести(ОбластьДанные);
Также для сокращения кода проверку на заполненность первой строки можно лаконично записать с помощью тернарного оператора ?():
СтрокаРезультат = "";
Пока Выборка.Следующий() Цикл
ТекущиеДанные = Строка(Выборка.Сотрудник) + " (" + Формат(Выборка.Начисление, "ДФ=dd.MM.yyyy") + ")";
СтрокаРезультат = СтрокаРезультат + ?(ЗначениеЗаполнено(СтрокаРезультат), ", ", "") + ТекущиеДанные;
КонецЦикла;
Бывают ситуации, когда нам нужно вывести строго список наименований (например, только фамилии сотрудников без сопутствующих дат или сумм) и у нас нет необходимости в сложном форматировании каждого элемента. В этом случае мы можем полностью отказаться от использования цикла Пока Выборка.Следующий().
Рассмотрим, как быстро получить массив значений напрямую из результата запроса:
// 1. Выгружаем результат запроса в Таблицу Значений
ТаблицаРезультата = Запрос.Выполнить().Выгрузить();
// 2. Получаем одномерный массив значений из конкретной колонки таблицы
МассивСотрудников = ТаблицаРезультата.ВыгрузитьКолонку("Сотрудник");
// 3. Объединяем массив в строку
СтрокаСотрудников = СтрСоединить(МассивСотрудников, ", ");
// 4. Передаем в макет
ОбластьДанные.Параметры.СписокСотрудников = СтрокаСотрудников;
ТабДок.Вывести(ОбластьДанные);
Этот способ экономит время разработки, сокращает объем кода и минимизирует количество строк, которые приходится писать вручную.
Если вы разрабатываете не просто ручную печатную форму, а полноценный отчет на базе Системы Компоновки Данных (СКД), то задача склеивания строк решается еще проще — с помощью встроенных функций ресурсов СКД.
Для этого в СКД предусмотрена специальная агрегатная функция СоединитьСтроки(). Рассмотрим порядок действий:
Сотрудник), в список ресурсов.СоединитьСтроки(Сотрудник, ", ").Даже если вы напишете идеальный программный код, который правильно собирает всех сотрудников в одну длинную строку, печатная форма может выглядеть неэстетично, если макет подготовлен неверно. По умолчанию ячейка табличного документа имеет фиксированный размер и при превышении длины строки текст либо скроется (обрежется), либо "наползет" на соседние ячейки.
Чтобы избежать подобных проблем визуализации, выполните следующие настройки в макете вашего документа:
.mxl).ТекстСотрудников). Поскольку строка может быть очень длинной, рекомендуется **объединить несколько ячеек по горизонтали**, создав широкую область для вывода текста.F4 или выберите пункт «Свойства» в контекстном меню).Text placement).Авто или Забивать. Измените его на значение «Переносить» (Wrap).После установки свойства «Переносить» табличный документ 1С будет автоматически анализировать длину полученной строки и переносить слова на новые строки, автоматически увеличивая высоту ячейки (и всей строки таблицы) по вертикали. Ваша печатная форма всегда будет выглядеть аккуратно, независимо от количества сотрудников в документе-источнике.