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

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

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

Разберем по шагам причины возникновения этой проблемы и рассмотрим несколько способов ее решения в рамках языка запросов 1С и типовых механизмов платформы.

Причины задвоения строк при соединении по представлению

Проанализируем структуру данных и ограничения языка запросов 1С:

  1. Множественность видов контактной информации: у одного контрагента или партнера может быть записано несколько одинаковых строковых адресов под разными видами контактной информации (например, «Юридический адрес», «Фактический адрес», «Адрес доставки 1»). При левом соединении по равенству представлений каждая строка документа сдублируется столько раз, сколько совпадений найдено в регистре.
  2. Ограничения на строковые поля: реквизит Представление в регистре контактной информации и строковые адреса в документах нередко имеют неограниченную длину. В языке запросов 1С поля неограниченной длины нельзя использовать в условиях соединения ПО, секциях ГДЕ и СГРУППИРОВАТЬ ПО без явного приведения через конструкцию ВЫРАЗИТЬ(... КАК СТРОКА(...)).
  3. Отсутствие оконных функций: в языке запросов платформы 1С нет аналитических функций (вроде ROW_NUMBER() OVER (...)), поэтому выбрать строго первую попавшуюся запись без дополнительной группировки прямым запросом невозможно.

Способ 1. Левое соединение с группировкой и агрегацией полей

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

Рассмотрим пример построения такого запроса:


ВЫБРАТЬ
    Реализация.Ссылка КАК Документ,
    Реализация.Контрагент КАК Контрагент,
    ВЫРАЗИТЬ(Реализация.АдресДоставки КАК СТРОКА(500)) КАК АдресДоставкиСтрока
ПОМЕСТИТЬ ВТ_Документы
ИЗ
    Документ.РеализацияТоваровУслуг КАК Реализация
ГДЕ
    Реализация.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
;

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

Важный момент: приведение полей к строке фиксированной длины через ВЫРАЗИТЬ(... КАК СТРОКА(500)) обязательно для корректной работы условий соединения и группировки.

Способ 2. Приоритезация видов контактной информации

Если у контрагента детальные поля для разных видов контактной информации могут различаться, необходимо задать четкий приоритет выбора. Например, в первую очередь брать адрес доставки, во вторую — фактический адрес, в третью — юридический.

Разберем реализацию схемы с приоритетами во временных таблицах:

  1. Выбираем документы и соединяем их с регистром контактной информации по выраженному представлению.
  2. Назначаем числовой приоритет каждому виду через конструкцию ВЫБОР КОГДА ... ТОГДА.
  3. Сворачиваем таблицу по документу и берем МИНИМУМ(Приоритет).
  4. Повторно связываем полученную таблицу с исходной контактной информацией по документу и вычисленному минимальному приоритету.

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


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

ВЫБРАТЬ
    ВТ.Документ КАК Документ,
    МИНИМУМ(ВТ.Приоритет) КАК МинПриоритет
ПОМЕСТИТЬ ВТ_ЛучшийПриоритет
ИЗ
    ВТ_Совпадения КАК ВТ
СГРУППИРОВАТЬ ПО
    ВТ.Документ
;

ВЫБРАТЬ
    Лучшие.Документ КАК Документ,
    МАКСИМУМ(ВсеСовпадения.Поле1) КАК Город,
    МАКСИМУМ(ВсеСовпадения.Поле2) КАК Улица
ИЗ
    ВТ_ЛучшийПриоритет КАК Лучшие
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_Совпадения КАК ВсеСовпадения
        ПО Лучшие.Документ = ВсеСовпадения.Документ
        И Лучшие.МинПриоритет = ВсеСовпадения.Приоритет
СГРУППИРОВАТЬ ПО
    Лучшие.Документ

Способ 3. Использование типовых программных механизмов

В современных конфигурациях 1С (на базе БСП) контактная информация хранится в виде сериализованного JSON или XML в реквизите ЗначенияПолей. Прямой разбор такой строки в запросе не всегда удобен и надежен.

Если отчет формируется с помощью СКД или программной обработки:

  1. В запросе получаем ссылку на документ, контрагента и текстовое представление адреса или поле ЗначенияПолей.
  2. В постобработке или вычисляемых полях СКД вызываем экспортные функции общего модуля УправлениеКонтактнойИнформацией или УправлениеКонтактнойИнформациейКлиентСервер, передавая туда строку адреса для разбора в структуру.
  3. Заполняем требуемые колонки отчета готовыми значениями без риска задвоения строк в запросе.
← На главную