Как объединить контактную информацию в одну строку при выводе данных в 1С?

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

Часто при разработке отчетов или печатных форм в 1С возникает задача: вывести данные договора и всю контактную информацию контрагента (телефоны, адреса электронной почты) в одну строку. Стандартный подход с использованием ЛЕВОГО СОЕДИНЕНИЯ в запросе часто приводит к эффекту декартова произведения: если у контрагента занесено три номера телефона и два адреса электронной почты, запрос вернет шесть строк с дублирующимися данными договора. Рассмотрим, как избежать этой ошибки и эффективно собрать данные.

Разбор причины появления дублей

Главная причина дублей — это попытка соединить «многие-ко-многим» в рамках одного набора данных. Когда мы соединяем таблицу договоров с таблицами телефонов и адресов ЭП, 1С пытается сопоставить каждую запись из правой части с каждой записью из левой. Чтобы избежать этого, нам нужно изменить подход к получению данных и их обработке.

Решение через пакетные запросы

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

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

Рассмотрим пример реализации такого алгоритма в коде:


// Создаем запрос с пакетом
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ Договор, Контрагент ИЗ ...; // Первый запрос
    |ВЫБРАТЬ Контрагент, Телефон ИЗ ...; // Второй запрос (телефоны)
    |ВЫБРАТЬ Контрагент, АдресЭП ИЗ ..."; // Третий запрос (адреса)

РезультатПакет = Запрос.ВыполнитьПакет();
ВыборкаДоговоры = РезультатПакет[0].Выбрать();
ВыборкаТелефоны = РезультатПакет[1].Выбрать();
ВыборкаАдреса = РезультатПакет[2].Выбрать();

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

Использование функционала Итоги

Если вы не хотите использовать пакетные запросы, можно воспользоваться встроенным механизмом ИТОГИ. Этот метод позволяет сгруппировать данные еще на этапе выполнения запроса к СУБД. При обходе результата с использованием ОбходРезультатаЗапроса.ПоГруппировкам, система сама создаст иерархию данных.

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

Оптимизация сборки строк с помощью СтрСоединить

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

Преимущества данного подхода:

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

← На главную