Как правильно получить несколько видов контактной информации контрагента в одном запросе 1С?

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

При разработке отчетов или выборок данных программисты часто сталкиваются с задачей вывода нескольких видов контактной информации (например, юридического и фактического адресов) в одну строку рядом с наименованием контрагента. На первый взгляд задача кажется тривиальной, но она таит в себе подводные камни, связанные с особенностями работы SQL-запросов и платформы 1С. Разберем типичную ситуацию, когда данные «исчезают» при добавлении очередного соединения, и выясним, как написать этот запрос максимально эффективно.

Анализ основной ошибки: почему пропадают данные?

Рассмотрим ситуацию, с которой столкнулся автор темы. В его исходном запросе использовалось ЛЕВОЕ СОЕДИНЕНИЕ с регистром сведений КонтактнаяИнформация, но результат выборки оказывался пустым. Проанализируем причину. Основная проблема заключается в использовании секции ГДЕ для фильтрации данных из правой (присоединяемой) таблицы.

Когда мы пишем условие КонтактнаяИнформация.Вид = &ВидФакт в секции ГДЕ, мы фактически превращаем наше ЛЕВОЕ СОЕДИНЕНИЕ во ВНУТРЕННЕЕ. Происходит это по следующей причине: если у контрагента нет записи о фактическом адресе, то во всех полях таблицы КИ для этой строки будет значение NULL. Проверка NULL = &ВидФакт всегда дает отрицательный результат, и вся строка исключается из итоговой выборки. В итоге, если у контрагента отсутствует хотя бы один из запрашиваемых адресов, он просто не попадает в результат.

Важное правило: условия фильтрации по правой таблице в левом соединении должны располагаться не в ГДЕ, а непосредственно в условии связи ПО.

Решение №1: Использование временных таблиц и корректных соединений

Один из способов решить задачу «в лоб» — это последовательное создание временных таблиц для каждого вида информации. Рассмотрим, как это реализовать правильно, чтобы не потерять данные о контрагентах, у которых заполнен только один адрес или адреса отсутствуют вовсе.


// Шаг 1: Выбираем базовый список контрагентов
ВЫБРАТЬ
    Контрагенты.Ссылка,
    Контрагенты.ИНН
ПОМЕСТИТЬ ВТ_Контрагенты
ИЗ
    Справочник.Контрагенты КАК Контрагенты
ГДЕ
    НЕ Контрагенты.ПометкаУдаления;

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

////////////////////////////////////////////////////////////////////////////////
// Шаг 3: Собираем итоговую таблицу
ВЫБРАТЬ
    ВТ_Контрагенты.Ссылка,
    ВТ_ФактАдреса.ФактАдрес,
    ВЫРАЗИТЬ(КИ_Юр.Представление КАК СТРОКА(500)) КАК ЮрАдрес
ИЗ
    ВТ_Контрагенты КАК ВТ_Контрагенты
        ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ФактАдреса КАК ВТ_ФактАдреса
        ПО ВТ_Контрагенты.Ссылка = ВТ_ФактАдреса.Ссылка
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КонтактнаяИнформация КАК КИ_Юр
        ПО ВТ_Контрагенты.Ссылка = КИ_Юр.Объект
            И КИ_Юр.Вид = &ВидЮР

Обратите внимание, что в этом примере условия КИ.Вид = &ВидФакт перенесены в секцию ПО. Также мы использовали функцию ВЫРАЗИТЬ. Это критически важно, так как поле Представление может иметь неограниченную длину, что мешает корректной работе временных таблиц и группировок.

Решение №2 (Оптимальное): Метод «Свертки» через группировку

Множественные левые соединения с одной и той же большой таблицей (регистром КИ) могут негативно сказаться на производительности. Проанализируем более изящный способ, который часто называют «Pivot» или разворот строк в колонки. Вместо того чтобы соединять таблицу КИ несколько раз, мы прочитаем ее один раз, а затем «схлопнем» результат с помощью группировки.

Разберем этот метод по шагам:

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

Рассмотрим пример кода:


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

СГРУППИРОВАТЬ ПО
    Контрагенты.Ссылка,
    Контрагенты.ИНН

Преимущества этого подхода:

Дополнительные рекомендации по работе с КИ

Проанализируем еще несколько важных моментов, которые помогут избежать ошибок в будущем:

1. Использование БСП (Библиотека стандартных подсистем). В современных конфигурациях (ЕРП, УТ 11, БП 3.0) работа с контактной информацией сильно автоматизирована. Вместо прямых запросов к регистрам рассмотрите возможность использования функции УправлениеКонтактнойИнформацией.ПолучитьКонтактнуюИнформациюОбъектов(). Она позволяет получить все необходимые данные одной строкой кода, учитывая все нюансы хранения данных.

2. Место хранения данных. Помните, что в некоторых версиях конфигураций данные КИ могут храниться не в регистре сведений, а в табличных частях самих справочников. Перед написанием запроса обязательно проверьте структуру метаданных вашей программы.

3. Поля неограниченной длины. Всегда используйте ВЫРАЗИТЬ(... КАК СТРОКА(Х)) для строковых полей регистра КИ. Это не только позволит использовать группировку, но и значительно ускорит выполнение запроса в операциях сравнения и соединения.

4. Обработка пустых значений. Если вы хотите вместо NULL выводить пустую строку или текст «Адрес не заполнен», используйте функцию ЕСТЬNULL(Поле, ""). В итоговой таблице это будет выглядеть гораздо профессиональнее.

Подводя итог, можно сказать, что правильная работа с соединениями и понимание логики NULL — это база, на которой строится эффективная разработка в 1С. Используя метод группировки (Pivot), вы обеспечиваете высокую скорость работы системы и создаете надежный код.

← На главную