При работе со справочниками в 1С:Предприятии разработчики часто сталкиваются с задачей вывода контактной информации. В типовых конфигурациях адреса, телефоны, email и другие контакты хранятся в подчиненной таблице — табличной части справочника или в отдельном регистре сведений РегистрСведений.КонтактнаяИнформация. Каждому виду контакта соответствует отдельная строка.
Часто возникает задача: вывести данные контрагента так, чтобы его адрес и телефон находились в одной строке, но в разных колонках (например, для выгрузки в Excel или вывода в простой отчет). Если написать обычный запрос, система выдаст несколько строк для одного контрагента — одну строку с заполненным адресом и пустой колонкой телефона, и вторую строку с телефоном и пустым адресом. В этой статье мы подробно разберем, как решить эту задачу правильно, используя три различных подхода.
Этот метод является наиболее производительным, так как СУБД делает всего один проход по таблице контактной информации. Суть метода заключается в разделении записей по колонкам с помощью условия ВЫБОР и последующем «схлопывании» строк с помощью агрегатной функции МАКСИМУМ.
Разберем, почему у многих начинающих разработчиков не получается этот способ с первого раза. Если написать запрос без агрегатных функций, то для одного контрагента все равно вернутся две строки. Чтобы объединить их, необходимо использовать группировку. Поскольку текстовое значение адреса или телефона всегда «больше» пустой строки "" при сравнении, функция МАКСИМУМ выберет именно заполненную строку для каждого поля, отбросив пустые.
Проанализируем пример готового запроса:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Контрагент,
МАКСИМУМ(ВЫБОР
КОГДА КонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес)
ТОГДА КонтактнаяИнформация.Представление
ИНАЧЕ ""
КОНЕЦ) КАК ЗначениеАдрес,
МАКСИМУМ(ВЫБОР
КОГДА КонтактнаяИнформация.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
ТОГДА КонтактнаяИнформация.Представление
ИНАЧЕ ""
КОНЕЦ) КАК ЗначениеТелефон
ИЗ
Справочник.Контрагенты КАК Контрагенты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
ПО Контрагенты.Ссылка = КонтактнаяИнформация.Объект
СГРУППИРОВАТЬ ПО
Контрагенты.Ссылка
Преимущества метода:
МАКСИМУМ(ВЫБОР...) без добавления новых соединений.Этот способ основан на связывании основной таблицы контрагентов с таблицей контактной информации несколько раз — отдельно для каждого нужного типа контакта. Мы как бы создаем виртуальные таблицы адресов и телефонов и «приклеиваем» их к контрагенту.
При использовании этого метода крайне важно соблюдать одно золотое правило построения запросов в 1С: условия фильтрации по типу контактной информации должны находиться строго в секции ПО левого соединения, а не в секции ГДЕ!
Если вы по ошибке напишете условие фильтрации в секции ГДЕ, левое соединение превратится во внутреннее (INNER JOIN). В результате из итоговой выборки полностью исчезнут те контрагенты, у которых не заполнен хотя бы один из видов контактов (например, есть телефон, но не указан адрес).
Посмотрим на пример правильной реализации соединения:
ВЫБРАТЬ
Контрагенты.Ссылка КАК Контрагент,
ТаблицаАдресов.Представление КАК ЗначениеАдрес,
ТаблицаТелефонов.Представление КАК ЗначениеТелефон
ИЗ
Справочник.Contragents КАК Контрагенты
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК ТаблицаАдресов
ПО Контрагенты.Ссылка = ТаблицаАдресов.Объект
И ТаблицаАдресов.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Адрес)
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК ТаблицаТелефонов
ПО Контрагенты.Ссылка = ТаблицаТелефонов.Объект
И ТаблицаТелефонов.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
Преимущества метода:
СГРУППИРОВАТЬ ПО, что в некоторых случаях облегчает дальнейшую работу с итогами в СКД.Важное примечание по производительности: Если вам нужно вытащить 5 и более различных видов контактной информации, данный метод создаст большую нагрузку на СУБД из-за обилия соединений. В таких случаях лучше вернуться к первому методу с группировкой.
Если вы ведете разработку в современных типовых конфигурациях (таких как 1С:ERP, Управление торговлей 11, Бухгалтерия предприятия 3.0, ЗУП 3.0), писать прямые запросы к табличным частям или регистрам контактной информации считается плохим тоном (антипаттерном). Структура хранения этих данных в системе может динамически меняться от релиза к релизу.
В составе Библиотеки стандартных подсистем (БСП) есть готовый общий модуль УправлениеКонтактнойИнформацией, который берет на себя всю работу по получению и компоновке данных.
Для массового получения данных (например, при формировании отчета или подготовке данных для списка) используем метод ТаблицаКонтактнойИнформацииОбъектов. Проанализируем пример кода на встроенном языке:
// 1. Формируем массив объектов, по которым нужны контакты
МассивКонтрагентов = Новый Массив;
МассивКонтрагентов.Добавить(СсылкаНаКонтрагента1);
МассивКонтрагентов.Добавить(СсылкаНаКонтрагента2);
// 2. Указываем, какие виды контактной информации нас интересуют
МассивВидовКИ = Новый Массив;
МассивВидовКИ.Добавить(Справочники.ВидыКонтактнойИнформации.ЮрАдресКонтрагента);
МассивВидовКИ.Добавить(Справочники.ВидыКонтактнойИнформации.ТелефонКонтрагента);
// 3. Вызываем стандартный метод БСП
ТаблицаРезультат = УправлениеКонтактнойИнформацией.ТаблицаКонтактнойИнформацииОбъектов(МассивКонтрагентов, МассивВидовКИ);
// На выходе мы получаем Таблицу Значений, где для каждого контрагента
// сформирована ровно ОДНА строка, а адреса и телефоны разнесены по колонкам.
Для Каждого СтрокаДанных Из ТаблицаРезультат Цикл
Сообщить("Контрагент: " + СтрокаДанных.Объект
+ " | Адрес: " + СтрокаДанных.ЮрАдресКонтрагента
+ " | Телефон: " + СтрокаДанных.ТелефонКонтрагента);
КонецЦикла;
Преимущества метода БСП:
Выбирайте наиболее подходящий метод исходя из архитектуры вашего решения: для нетиповых самописных баз идеально подойдет Метод 1, а для современных систем на базе БСП лучшим решением будет использование программного интерфейса из Метода 3.