При построении отчетов в конфигурациях на базе «Библиотеки стандартных подсистем» (таких как «1С:Управление торговлей 11», «1С:ERP» или «1С:Комплексная автоматизация») разработчики часто сталкиваются с задачей вывести контактные данные контрагента или контактного лица в одну строчку. Вместо желаемой компактной строки видны две или более повторяющиеся записи: в одной заполнен только телефон, а во второй — только email.
Разберем природу этой проблемы, проанализируем ошибки при сложении строк в запросе и рассмотрим несколько надежных вариантов решения задачи средствами языка запросов 1С и системы компоновки данных.
В современных конфигурациях 1С контактная информация хранится в табличных частях объектов (например, КонтактныеЛицаПартнеров.КонтактнаяИнформация) либо в регистре сведений КонтактнаяИнформация. Каждое средство связи (номер телефона, адрес электронной почты, юридический адрес) хранится в отдельной строке табличной части.
Когда мы обращаемся напрямую к табличной части через запрос:
ВЫБРАТЬ
КИ.Ссылка КАК КонтактноеЛицо,
КИ.НомерТелефона КАК НомерТелефона,
КИ.АдресЭП КАК АдресЭП
ИЗ
Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК КИ
СУБД возвращает ровно столько строк, сколько записей заведено у контакта. В строке с телефонным номером поле АдресЭП будет пустым, а в строке с почтой пустым окажется НомерТелефона. Попытка просто сложить эти поля через + приведет либо к ошибке несовместимости типов, либо к результату со значениями NULL и «висячими» запятыми.
Также важно помнить об особенностях платформы при конкатенации строк в запросе:
+ можно только строки ограниченной длины. Если поле имеет неограниченную длину, его необходимо явно приводить с помощью функции ВЫРАЗИТЬ(Поле КАК СТРОКА(Длина)).NULL, весь итоговый результат сложения превратится в NULL. Поэтому обязательна обработка функцией ЕСТЬNULL.Рассмотрим наиболее производительный и универсальный способ для языка запросов. Чтобы не делать лишних соединений к одной и той же таблице, мы можем сгруппировать данные по контактному лицу и применить агрегатную функцию МАКСИМУМ к полям с отбором по типу контактной информации.
Разберем текст запроса, где во вложенной таблице мы распределяем значения по колонкам, а во внешнем запросе аккуратно соединяем их с проверкой на пустоту:
ВЫБРАТЬ
ВложенныйЗапрос.КонтактноеЛицо КАК КонтактноеЛицо,
ВЫБОР
КОГДА ВложенныйЗапрос.Телефон <> "" И ВложенныйЗапрос.Почта <> ""
ТОГДА ВложенныйЗапрос.Телефон + ", " + ВложенныйЗапрос.Почта
КОГДА ВложенныйЗапрос.Телефон <> ""
ТОГДА ВложенныйЗапрос.Телефон
ИНАЧЕ ВложенныйЗапрос.Почта
КОНЕЦ КАК СредстваСвязи
ИЗ
(ВЫБРАТЬ
КИ.Ссылка КАК КонтактноеЛицо,
МАКСИМУМ(ВЫБОР
КОГДА КИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон)
ТОГДА ВЫРАЗИТЬ(КИ.НомерТелефона КАК СТРОКА(50))
ИНАЧЕ ""
КОНЕЦ) КАК Телефон,
МАКСИМУМ(ВЫБОР
КОГДА КИ.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты)
ТОГДА ВЫРАЗИТЬ(КИ.АдресЭП КАК СТРОКА(100))
ИНАЧЕ ""
КОНЕЦ) КАК Почта
ИЗ
Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК КИ
СГРУППИРОВАТЬ ПО
КИ.Ссылка) КАК ВложенныйЗапрос
Такой подход гарантирует, что на каждое контактное лицо вернется ровно одна строка, а запятая между телефоном и почтой появится только тогда, когда заполнены оба средства связи.
Проанализируем классический прием, когда к основной таблице справочника присоединяются отдельные экземпляры контактных данных с фильтром по типу или виду. В конфигурации «Управление торговлей 11» источником служит табличная часть справочника контактных лиц.
Посмотрим на пример запроса:
ВЫБРАТЬ
Контакты.Ссылка КАК КонтактноеЛицо,
ВЫБОР
КОГДА КИ_Телефон.НомерТелефона ЕСТЬ НЕ NULL И КИ_Почта.АдресЭП ЕСТЬ НЕ NULL
ТОГДА ВЫРАЗИТЬ(КИ_Телефон.НомерТелефона КАК СТРОКА(50)) + ", " + ВЫРАЗИТЬ(КИ_Почта.АдресЭП КАК СТРОКА(100))
КОГДА КИ_Телефон.НомерТелефона ЕСТЬ НЕ NULL
ТОГДА ВЫРАЗИТЬ(КИ_Телефон.НомерТелефона КАК СТРОКА(50))
ИНАЧЕ ЕСТЬNULL(ВЫРАЗИТЬ(КИ_Почта.АдресЭП КАК СТРОКА(100)), "")
КОНЕЦ КАК СредстваСвязи
ИЗ
Справочник.КонтактныеЛицаПартнеров КАК Контакты
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК КИ_Телефон
ПО Контакты.Ссылка = КИ_Телефон.Ссылка
И (КИ_Телефон.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон))
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК КИ_Почта
ПО Контакты.Ссылка = КИ_Почта.Ссылка
И (КИ_Почта.Тип = ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты))
Обратите внимание: если у одного контактного лица в базе зарегистрировано несколько телефонов, левое соединение размножит строки. Если существует вероятность ввода нескольких однотипных контактов, лучше использовать группировку из первого способа либо функционал СКД.
Если разработка отчета ведется в Системе компоновки данных, писать сложные конструкции с конкатенацией строк в самом тексте запроса не обязательно. В СКД встроен агрегатный метод СоединитьСтроки, который берет на себя объединение значений.
Разберем по шагам настройку схемы компоновки данных:
КонтактноеЛицо и строковое представление контакта:
ВЫБРАТЬ
КИ.Ссылка КАК КонтактноеЛицо,
КИ.Представление КАК КонтактнаяИнформация
ИЗ
Справочник.КонтактныеЛицаПартнеров.КонтактнаяИнформация КАК КИ
ГДЕ
КИ.Тип В (
ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.Телефон),
ЗНАЧЕНИЕ(Перечисление.ТипыКонтактнойИнформации.АдресЭлектроннойПочты)
)
КонтактнаяИнформация в список ресурсов и укажите в выражении:
СоединитьСтроки(КонтактнаяИнформация, ", ")КонтактноеЛицо, а саму группировку Детальные записи исключите из структуры.При формировании отчета СКД автоматически свернет строки по каждому контактному лицу, исключит пустые значения и выведет все имеющиеся средства связи через запятую в одну аккуратную строку.