Часто при разработке отчетов или печатных форм в 1С возникает задача: вывести данные договора и всю контактную информацию контрагента (телефоны, адреса электронной почты) в одну строку. Стандартный подход с использованием ЛЕВОГО СОЕДИНЕНИЯ в запросе часто приводит к эффекту декартова произведения: если у контрагента занесено три номера телефона и два адреса электронной почты, запрос вернет шесть строк с дублирующимися данными договора. Рассмотрим, как избежать этой ошибки и эффективно собрать данные.
Главная причина дублей — это попытка соединить «многие-ко-многим» в рамках одного набора данных. Когда мы соединяем таблицу договоров с таблицами телефонов и адресов ЭП, 1С пытается сопоставить каждую запись из правой части с каждой записью из левой. Чтобы избежать этого, нам нужно изменить подход к получению данных и их обработке.
Наиболее надежный способ — это выполнение Запрос.ВыполнитьПакет(). Разделив логику получения данных, мы избавимся от лишних соединений. Давайте разберем пошагово, как реализовать этот алгоритм:
ЭП, привязанные к этим контрагентам.Рассмотрим пример реализации такого алгоритма в коде:
// Создаем запрос с пакетом
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ Договор, Контрагент ИЗ ...; // Первый запрос
|ВЫБРАТЬ Контрагент, Телефон ИЗ ...; // Второй запрос (телефоны)
|ВЫБРАТЬ Контрагент, АдресЭП ИЗ ..."; // Третий запрос (адреса)
РезультатПакет = Запрос.ВыполнитьПакет();
ВыборкаДоговоры = РезультатПакет[0].Выбрать();
ВыборкаТелефоны = РезультатПакет[1].Выбрать();
ВыборкаАдреса = РезультатПакет[2].Выбрать();
Пока ВыборкаДоговоры.Следующий() Цикл
// Используем массивы для формирования строк
МассивТелефонов = Новый Массив;
// Ищем телефоны для текущего контрагента
ВыборкаТелефоны.Сбросить();
СтруктураОтбора = Новый Структура("Контрагент", ВыборкаДоговоры.Контрагент);
Пока ВыборкаТелефоны.НайтиСледующий(СтруктураОтбора) Цикл
МассивТелефонов.Добавить(ВыборкаТелефоны.Телефон);
КонецЦикла;
СтрокаТелефонов = СтрСоединить(МассивТелефонов, ", ");
// Аналогично поступаем с адресами ЭП
КонецЦикла;
Если вы не хотите использовать пакетные запросы, можно воспользоваться встроенным механизмом ИТОГИ. Этот метод позволяет сгруппировать данные еще на этапе выполнения запроса к СУБД. При обходе результата с использованием ОбходРезультатаЗапроса.ПоГруппировкам, система сама создаст иерархию данных.
При использовании этого метода, при обходе группировки «Договор» или «Контрагент», вы получаете доступ к вложенной выборке (детальным записям). Это позволяет избежать дублирования строк на верхнем уровне, так как деление на телефоны происходит уже внутри цикла.
Для того чтобы код выглядел аккуратно и работал быстро, используйте функцию СтрСоединить. Она позволяет передать массив значений и разделитель, автоматически расставляя запятые только между элементами. Это избавляет от необходимости писать условия типа Если НачалоСтроки Тогда ... Иначе ... и вручную удалять лишние символы в конце строки с помощью функций Лев или Прав.
Преимущества данного подхода:
Используя предложенные методы, вы сможете сформировать отчеты любой сложности без дублей и ошибок. Если данных очень много, помните, что поиск через НайтиСледующий по выборке эффективнее работает, если предварительно выгрузить результаты дополнительных запросов в ТаблицуЗначений с установленным индексом по колонке «Контрагент».