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