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

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

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

В этой статье мы подробно разберем, почему возникает эта проблема, и рассмотрим несколько эффективных способов ее решения: от простых отборов в запросе до продвинутого группирования и использования механизмов Системы компоновки данных (СКД) или программных методов БСП.

Выясняем причину: почему запрос выдает несколько строк на одного человека?

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

Попытка использовать конструкцию СГРУППИРОВАТЬ ПО без наложения жестких условий на виды контактной информации не решит проблему, так как поля «Номер телефона» в этих строках разные, и группировка просто оставит обе строки без изменений.


Решение 1. Фильтрация по конкретному виду контактной информации

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

Рассмотрим пример правильного построения запроса с левым соединением и жестким отбором по виду контактной информации:


ВЫБРАТЬ
    Студенты.Ссылка КАК Студент,
    ЕСТЬNULL(КонтактыСтудента.НомерТелефона, "Телефон не указан") КАК НомерТелефона
ИЗ
    Справочник.Студенты КАК Студенты
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Студенты.КонтактнаяИнформация КАК КонтактыСтудента
        ПО Студенты.Ссылка = КонтактыСтудента.Ссылка
        И КонтактыСтудента.Вид = &ВидТелефона
ГДЕ
    Студенты.Пол = &Пол

Важный нюанс: обратите внимание, что условие отбора по виду КИ (КонтактыСтудента.Вид = &ВидТелефона) мы поместили в секцию связи ПО, а не в секцию ГДЕ. Это сделано для того, чтобы при левом соединении студенты, у которых вообще не заполнен телефон, все равно попали в итоговую выборку (для них выведется текст "Телефон не указан"). Если бы мы написали этот отбор в секции ГДЕ, левое соединение превратилось бы во внутреннее, и студенты без телефонов пропали бы из результата.


Решение 2. Транспонирование строк в колонки (Метод «МАКСИМУМ(ВЫБОР...)»)

Что делать, если нам нужно вывести на экран одновременно несколько разных телефонов (например, и мобильный, и домашний), но при этом мы хотим, чтобы на каждого студента приходилась строго одна строка?

Для решения этой задачи мы можем применить классический SQL-прием разворачивания строк в колонки (транспонирование). Разберем по шагам, как это реализовать с помощью конструкции ВЫБОР и агрегатной функции МАКСИМУМ:


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

Как это работает: мы группируем весь результат по уникальной ссылке студента. Внутри полей выбора конструкция ВЫБОР отсекает все типы контактов, кроме нужного. Функция МАКСИМУМ выбирает среди пустых строк и единственного заполненного значения именно заполненный номер телефона. В итоге мы получаем красивую таблицу, где каждому человеку соответствует ровно одна строка, а его контакты разложены по соответствующим колонкам.


Решение 3. Использование множественных левых соединений

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

Посмотрим на пример реализации данного метода:


ВЫБРАТЬ
    Студенты.Ссылка КАК Студент,
    ЕСТЬNULL(ТелефонМобильный.НомерТелефона, "") КАК МобильныйТелефон,
    ЕСТЬNULL(ТелефонДомашний.НомерТелефона, "") КАК ДомашнийТелефон
ИЗ
    Справочник.Студенты КАК Студенты
    
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Студенты.КонтактнаяИнформация КАК ТелефонМобильный
        ПО Студенты.Ссылка = ТелефонМобильный.Ссылка
        И ТелефонМобильный.Вид = &ВидМобильный
        
    ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Студенты.КонтактнаяИнформация КАК ТелефонДомашний
        ПО Студенты.Ссылка = ТелефонДомашний.Ссылка
        И ТелефонДомашний.Вид = &ВидДомашний

Преимущества и недостатки: этот метод визуально проще для понимания, чем группировка с МАКСИМУМ. Однако помните, что если в базе данных по ошибке пользователем будет введено два мобильных телефона для одного студента, то строки снова начнут двоиться. Метод с группировкой (Решение 2) в этом плане более защищен от ошибок ввода.


Решение 4. Вывод контактов через запятую в СКД (Системе компоновки данных)

Если вы разрабатываете отчет на СКД, то самым красивым и простым решением будет объединение всех номеров телефонов в одну ячейку через запятую. Платформа 1С предоставляет для этого встроенную функцию агрегации.

Разберем алгоритм настройки этого механизма:

  1. В схеме компоновки данных (СКД) добавьте стандартный запрос, получающий список студентов и их номера телефонов (без группировок).
  2. Перейдите на вкладку «Ресурсы» вашей схемы компоновки.
  3. Добавьте поле НомерТелефона в список ресурсов.
  4. В поле «Выражение» напишите следующую формулу:
    СоединитьСтроки(Массив(Различные НомерТелефона), ", ")
  5. В настройках структуры отчета (вкладка «Настройки») добавьте группировку по полю Студент, а поле НомерТелефона выведите в качестве выбранных полей. Детальные записи (группировку «Детальные записи») добавлять не нужно.

Использование конструкции Массив(Различные ...) гарантирует, что даже если один и тот же номер телефона был случайно записан студенту дважды, в итоговом отчете он отобразится в единственном экземпляре.


Решение 5. Использование программных механизмов БСП (Библиотеки Стандартных Подсистем)

В современных типовых конфигурациях 1С (таких как УТ, ERP, КА, БП, ЗУП) контактная информация хранится в стандартизированном виде под управлением БСП. Зачастую в табличных частях находится не просто строка с номером, а сложная XML- или JSON-структура. Напрямую извлекать ее запросом не рекомендуется.

Для программного получения очищенных от дублей контактных данных разработчики используют готовые методы общего модуля УправлениеКонтактнойИнформацией.

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


// Создаем массив объектов, для которых нужно получить контакты
МассивОбъектов = Новый Массив;
МассивОбъектов.Добавить(СсылкаНаСтудента1);
МассивОбъектов.Добавить(СсылкаНаСтудента2);

// Определяем типы и виды контактной информации
ВидыКИ = Новый Массив;
ВидыКИ.Добавить(Справочники.ВидыКонтактнойИнформации.ТелефонМобильный);

// Получаем таблицу с готовыми представлениями контактов
ТаблицаКонтактов = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъектов(МассивОбъектов, , ВидыКИ);

// Обходим результат без дублирования строк на каждого студента
Для Каждого СтрокаКонтакта Из ТаблицаКонтактов Цикл
    Сообщить("Студент: " + СтрокаКонтакта.Объект + " - Телефон: " + СтрокаКонтакта.Представление);
КонецЦикла;

Этот метод работает быстро, оптимизирован на уровне СУБД, автоматически распаковывает JSON/XML хранилища БСП и возвращает готовую плоскую таблицу значений, которую вы можете легко связать со своими исходными данными.

Выбирайте наиболее подходящий для вашей задачи метод: фильтрацию на уровне условий связи, транспонирование с помощью группировок, агрегацию средствами компоновки данных или готовые функции БСП. Это позволит вашим отчетам и обработкам работать быстро, а пользователям — видеть корректные данные без лишних строк.

← На главную