Как вывести номер телефона из табличной части в динамический список справочника «Физические лица»?

Программист IT и автоматизация бизнеса
← На главную

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

Метод 1. Использование прямого левого соединения в запросе

Самый простой и очевидный способ получить данные из табличной части — это использование конструкции ЛЕВОЕ СОЕДИНЕНИЕ. Однако при работе с динамическим списком важно помнить, что он не поддерживает пакетные запросы с использованием временных таблиц (конструкция ПОМЕСТИТЬ). Весь запрос должен быть представлен в виде единого селекта.

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


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

Разберем по шагам важные детали этого запроса:

  1. Левое соединение: Мы используем именно ЛЕВОЕ СОЕДИНЕНИЕ, так как если у физического лица не заполнен телефон, оно все равно должно отображаться в списке. При использовании внутреннего соединения (СОЕДИНЕНИЕ) из списка пропадут все лица без телефонов.
  2. Условия в секции ПО: Обратите внимание, что фильтры по типу и виду контактной информации наложены прямо в условии соединения. Это позволяет СУБД сначала отфильтровать таблицу КонтактнаяИнформация, а затем соединить её с основной таблицей.
  3. Функция ЕСТЬNULL: Если телефон не найден, запрос вернет значение NULL. Чтобы в колонке списка корректно отображалась пустая строка, мы используем ЕСТЬNULL(Контакты.НомерТелефона, "").

Метод 2. Защита от дублирования строк (группировка)

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

Чтобы гарантировать уникальность строк, мы должны соединяться не с самой табличной частью, а с вложенным запросом, в котором выполнена группировка. Выясним причину популярности этого метода: он гарантирует результат «одна строка — один объект».


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

В данном примере функция МАКСИМУМ выберет один из имеющихся номеров, если их несколько, и предотвратит «размножение» строк в интерфейсе.

Особенности работы с БСП и регистрами сведений

Если вы работаете в современной конфигурации (например, ЗУП 3.1, ERP 2.5 или УТ 11), важно знать, что контактная информация часто хранится не только (или не столько) в табличных частях, сколько в специальном регистре сведений КонтактнаяИнформация. Рассмотрим подробнее преимущества работы с ним:

Запрос к регистру в динамическом списке будет выглядеть аналогично соединению с табличной частью, но вместо Справочник.ФизическиеЛица.КонтактнаяИнформация мы обратимся к РегистрСведений.КонтактнаяИнформация.

Программный вывод через событие «ПриПолученииДанныхНаСервере»

Иногда запросы в динамических списках становятся слишком тяжелыми, что приводит к «подтормаживанию» при прокрутке. Если данных очень много, проанализируем альтернативный путь — программное заполнение колонки. Мы можем добавить в динамический список незаполненную колонку (путь к данным не указан) и заполнять её в событии ПриПолученииДанныхНаСервере.

Алгоритм действий следующий:

  1. Добавляем в список колонку ТелефонСтрокой.
  2. В модуле формы прописываем обработчик события.

&НаСервере
Процедура СписокПриПолученииДанныхНаСервере(ИмяЭлемента, Настройки, Строки)
    
    // Собираем ссылки на физлица, которые сейчас видны на экране
    МассивСсылок = Строки.ПолучитьКлючи();
    
    // Получаем телефоны одним запросом только для видимых строк
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |   КИ.Объект КАК Ссылка,
        |   КИ.Представление КАК Телефон
        |ИЗ
        |   РегистрСведений.КонтактнаяИнформация КАК КИ
        |ГДЕ
        |   КИ.Объект В(&МассивСсылок)
        |   И КИ.Вид = &Вид";
    
    Запрос.УстановитьПараметр("МассивСсылок", МассивСсылок);
    Запрос.УстановитьПараметр("Вид", Справочники.ВидыКонтактнойИнформации.ТелефонФизЛица);
    
    Выборка = Запрос.Выполнить().Выбрать();
    
    // Заполняем данные в строках динамического списка
    Пока Выборка.Следующий() Цикл
        СтруктураДанных = Строки[Выборка.Ссылка];
        СтруктураДанных.Данные.ТелефонСтрокой = Выборка.Телефон;
    КонецЦикла;
    
КонецПроцедуры

Этот метод значительно эффективнее для СУБД, так как запрос выполняется не для всей таблицы из 100 000 записей, а только для тех 20–40 строк, которые пользователь видит в данный момент.

Важные рекомендации по оптимизации

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

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

← На главную