Как сгруппировать контактных лиц и избежать дублирования строк в запросе 1С?

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

При составлении отчетов или выборок данных по контрагентам и документам реализации разработчики часто сталкиваются с ситуацией, когда одна и та же строка документа многократно дублируется. Подобная проблема возникает при попытке одновременно получить контактную информацию контрагента (адрес, телефон) и список связанных с ним контактных лиц. Попытка решить проблему «в лоб» с помощью ключевых слов СГРУППИРОВАТЬ ПО или РАЗЛИЧНЫЕ обычно приводит к ошибкам платформы.

Разберем причины возникновения таких ошибок, проанализируем структуру запроса и рассмотрим проверенные способы корректного вывода контактных лиц без дублирования строк.

Анализ причин ошибок и декартова произведения

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

  1. Ошибка использования полей неограниченной длины: При добавлении ключевого слова РАЗЛИЧНЫЕ или при группировке по полю КонтактнаяИнформация.Представление платформа выдает ошибку: «В запросе с предложениями РАЗЛИЧНЫЕ или ОБЪЕДЕНИТЬ нельзя использовать поля неограниченной длины». Поле Представление в регистре сведений КонтактнаяИнформация имеет строковый тип неограниченной длины. СУБД не может выполнять сравнение и сортировку таких полей без явного ограничения длины.
  2. Эффект декартова произведения: Если у контрагента заполнено 3 вида контактной информации (например, юридический адрес, телефон, email) и создано 2 контактных лица, левое соединение двух независимых таблиц с отношением «один-ко-многим» приведет к формированию 6 строк (3 × 2) на один документ реализации. Ключевое слово РАЗЛИЧНЫЕ здесь не поможет, так как в каждой строке будет уникальная комбинация адреса и контактного лица.
  3. Отсутствие агрегации строк в языке запросов 1С: В синтаксисе запросов платформы 1С:Предприятие нет аналогов SQL-функций GROUP_CONCAT или STRING_AGG. Объединить несколько строк справочника в одну через запятую исключительно средствами самого текста запроса невозможно.
  4. Некорректные условия соединения: Связывание регистра контактной информации через поле Наименование вместо ссылки приводит к падению производительности и логическим ошибкам выборки, так как измерение Объект хранит ссылку на контрагента, а не строку.

Способ 1. Использование функции ВЫРАЗИТЬ для полей неограниченной длины

Если требуется применить ключевое слово РАЗЛИЧНЫЕ или выполнить конструкцию СГРУППИРОВАТЬ ПО для таблицы с контактной информацией, поле Представление необходимо явно привести к строке фиксированной длины.

Посмотрим на пример корректного приведения типа в запросе:


ВЫБРАТЬ РАЗЛИЧНЫЕ
    Реализация.Контрагент КАК Контрагент,
    КонтактнаяИнформация.Тип КАК Тип,
    КонтактнаяИнформация.Вид КАК Вид,
    ВЫРАЗИТЬ(КонтактнаяИнформация.Представление КАК Строка(1000)) КАК Представление
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
        ПО Реализация.Контрагент = КонтактнаяИнформация.Объект
ГДЕ
    КонтактнаяИнформация.Вид В (&МассивВидов)
    И Реализация.Ссылка = &ВыбРеализация

Важно: если поле используется в секции СГРУППИРОВАТЬ ПО, конструкция ВЫРАЗИТЬ(... КАК Строка(1000)) должна быть указана как в списке выборки, так и в блоке группировки.

Способ 2. Постобработка результата запроса на встроенном языке

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

Разберем по шагам алгоритм на встроенном языке 1С:

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

Посмотрим на пример кода постобработки:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   КонтактныеЛица.Владелец КАК Контрагент,
    |   КонтактныеЛица.Ссылка КАК КонтактноеЛицо
    |ИЗ
    |   Справочник.КонтактныеЛицаКонтрагентов КАК КонтактныеЛица
    |ГДЕ
    |   КонтактныеЛица.Владелец В(&МассивКонтрагентов)";

Запрос.УстановитьПараметр("МассивКонтрагентов", МассивКонтрагентов);
ТаблицаЛиц = Запрос.Выполнить().Выгрузить();

// Формируем соответствие контрагентов и объединенных строк контактных лиц
СоответствиеЛиц = Новый Соответствие;
Для Каждого СтрКонтрагент Из МассивКонтрагентов Цикл
    Отбор = Новый Структура("Контрагент", СтрКонтрагент);
    НайденныеСтроки = ТаблицаЛиц.НайтиСтроки(Отбор);
    
    МассивИмен = Новый Массив;
    Для Каждого СтрокаЛицо Из НайденныеСтроки Цикл
        МассивИмен.Добавить(Строка(СтрокаЛицо.КонтактноеЛицо));
    КонецЦикла;
    
    СоответствиеЛиц.Вставить(СтрКонтрагент, СтрСоединить(МассивИмен, ", "));
КонецЦикла;

Способ 3. Объединение контактных лиц средствами СКД

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

Проанализируем порядок настройки отчета в СКД:

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

Способ 4. Получение только основного контактного лица

Если для задачи не требуется полный перечень всех представителей контрагента, а нужно вывести только ответственное лицо, оптимально исключить связь «один-ко-многим» еще на этапе составления запроса:

  1. Проверяем наличие в справочнике Контрагенты реквизита ОсновноеКонтактноеЛицо.
  2. Связываем документ реализации напрямую со справочником контрагентов и берем реквизит Контрагент.ОсновноеКонтактноеЛицо, избегая лишних соединений с подчиненным справочником.

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

← На главную