Как объединить несколько записей контактной информации в одну строку с разными полями в запросе 1С

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

При работе со справочниками в 1С:Предприятии разработчики часто сталкиваются с задачей вывода контактной информации. В типовых конфигурациях адреса, телефоны, email и другие контакты хранятся в подчиненной таблице — табличной части справочника или в отдельном регистре сведений РегистрСведений.КонтактнаяИнформация. Каждому виду контакта соответствует отдельная строка.

Часто возникает задача: вывести данные контрагента так, чтобы его адрес и телефон находились в одной строке, но в разных колонках (например, для выгрузки в Excel или вывода в простой отчет). Если написать обычный запрос, система выдаст несколько строк для одного контрагента — одну строку с заполненным адресом и пустой колонкой телефона, и вторую строку с телефоном и пустым адресом. В этой статье мы подробно разберем, как решить эту задачу правильно, используя три различных подхода.

Метод 1. Использование конструкции ВЫБОР КОГДА и группировки (Рекомендуемый в запросах)

Этот метод является наиболее производительным, так как СУБД делает всего один проход по таблице контактной информации. Суть метода заключается в разделении записей по колонкам с помощью условия ВЫБОР и последующем «схлопывании» строк с помощью агрегатной функции МАКСИМУМ.

Разберем, почему у многих начинающих разработчиков не получается этот способ с первого раза. Если написать запрос без агрегатных функций, то для одного контрагента все равно вернутся две строки. Чтобы объединить их, необходимо использовать группировку. Поскольку текстовое значение адреса или телефона всегда «больше» пустой строки "" при сравнении, функция МАКСИМУМ выберет именно заполненную строку для каждого поля, отбросив пустые.

Проанализируем пример готового запроса:


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

Преимущества метода:

  1. Высокая скорость выполнения (минимальное количество соединений таблиц).
  2. Легко масштабируется: если потребуется добавить еще одно поле (например, Email), достаточно дописать еще одну конструкцию МАКСИМУМ(ВЫБОР...) без добавления новых соединений.

Метод 2. Левое соединение таблицы «самой на себя»

Этот способ основан на связывании основной таблицы контрагентов с таблицей контактной информации несколько раз — отдельно для каждого нужного типа контакта. Мы как бы создаем виртуальные таблицы адресов и телефонов и «приклеиваем» их к контрагенту.

При использовании этого метода крайне важно соблюдать одно золотое правило построения запросов в 1С: условия фильтрации по типу контактной информации должны находиться строго в секции ПО левого соединения, а не в секции ГДЕ!

Если вы по ошибке напишете условие фильтрации в секции ГДЕ, левое соединение превратится во внутреннее (INNER JOIN). В результате из итоговой выборки полностью исчезнут те контрагенты, у которых не заполнен хотя бы один из видов контактов (например, есть телефон, но не указан адрес).

Посмотрим на пример правильной реализации соединения:


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

Преимущества метода:

  1. Запрос выглядит очень просто и легко читается разработчиками.
  2. Нет необходимости использовать секцию СГРУППИРОВАТЬ ПО, что в некоторых случаях облегчает дальнейшую работу с итогами в СКД.

Важное примечание по производительности: Если вам нужно вытащить 5 и более различных видов контактной информации, данный метод создаст большую нагрузку на СУБД из-за обилия соединений. В таких случаях лучше вернуться к первому методу с группировкой.

Метод 3. Современный стандарт разработки (через функции БСП)

Если вы ведете разработку в современных типовых конфигурациях (таких как 1С:ERP, Управление торговлей 11, Бухгалтерия предприятия 3.0, ЗУП 3.0), писать прямые запросы к табличным частям или регистрам контактной информации считается плохим тоном (антипаттерном). Структура хранения этих данных в системе может динамически меняться от релиза к релизу.

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

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


// 1. Формируем массив объектов, по которым нужны контакты
МассивКонтрагентов = Новый Массив;
МассивКонтрагентов.Добавить(СсылкаНаКонтрагента1);
МассивКонтрагентов.Добавить(СсылкаНаКонтрагента2);

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

// 3. Вызываем стандартный метод БСП
ТаблицаРезультат = УправлениеКонтактнойИнформацией.ТаблицаКонтактнойИнформацииОбъектов(МассивКонтрагентов, МассивВидовКИ);

// На выходе мы получаем Таблицу Значений, где для каждого контрагента 
// сформирована ровно ОДНА строка, а адреса и телефоны разнесены по колонкам.
Для Каждого СтрокаДанных Из ТаблицаРезультат Цикл
    Сообщить("Контрагент: " + СтрокаДанных.Объект 
        + " | Адрес: " + СтрокаДанных.ЮрАдресКонтрагента 
        + " | Телефон: " + СтрокаДанных.ТелефонКонтрагента);
КонецЦикла;

Преимущества метода БСП:

  1. Отказоустойчивость: ваш код не сломается при обновлении конфигурации 1С.
  2. Простота: не нужно писать громоздкие запросы со связями или группировками вручную.
  3. Метод автоматически учитывает историчность контактной информации (если она включена в системе) и особенности хранения различных типов КИ.

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

← На главную