При разработке интерфейсов на платформе 1С программисты часто сталкиваются с необходимостью вывести в динамический список данные из нескольких связанных таблиц. Типичная ситуация: у нас есть справочник (например, Запросы), и мы хотим отобразить рядом с каждым запросом данные о последнем взаимодействии (например, Телефонный звонок) и его статус из регистра сведения. Однако при простом соединении таблиц строки начинают дублироваться, а нужные поля остаются пустыми. В этой статье мы подробно разберем, как правильно составить запрос для динамического списка, чтобы избежать этих проблем.
Прежде чем переходить к коду, проанализируем причину возникновения проблемы. В реляционных базах данных соединение типа ЛЕВОЕ СОЕДИНЕНИЕ (LEFT JOIN) работает по принципу соответствия. Если одной записи в главной таблице (справочник Запросы) соответствует несколько записей в подчиненной таблице (документ ТелефонныйЗвонок), система создаст в результирующей выборке столько строк, сколько найдено соответствий. Для динамического списка это критично, так как пользователь видит одну и ту же заявку несколько раз, что затрудняет работу.
Также важно помнить о свойстве Основная таблица динамического списка. Если запрос содержит группировки или ключевое слово РАЗЛИЧНЫЕ, система может потерять связь с основной таблицей, что приведет к невозможности стандартного поиска, отбора и сортировки.
Рассмотрим наиболее прямолинейный способ решения проблемы, когда нам нужно получить данные о взаимодействиях, не допуская размножения строк. Мы можем сгруппировать результат по всем полям основной таблицы и выбрать максимальные значения для полей из подчиненных таблиц.
Посмотрим на пример запроса, который позволяет корректно вывести данные:
ВЫБРАТЬ РАЗЛИЧНЫЕ
СправочникЗапросы.Наименование,
СправочникЗапросы.ВидЗапроса,
СправочникЗапросы.ДатаСоздания,
СправочникЗапросы.Имя,
СправочникЗапросы.Источник,
ВЫРАЗИТЬ(СправочникЗапросы.Описание КАК СТРОКА(1000)) КАК Описание,
СправочникЗапросы.Ответственный,
СправочникЗапросы.РегионКлиента,
СправочникЗапросы.Статус,
СправочникЗапросы.Телефон,
СправочникЗапросы.ЭлектроннаяПочта,
СправочникЗапросы.Ссылка КАК Ссылка,
МАКСИМУМ(ТелефонныйЗвонок.Ссылка) КАК СсылкаДокумент,
МАКСИМУМ(ПредметыПапкиВзаимодействий.Рассмотрено) КАК Рассмотрено,
МАКСИМУМ(ПредметыПапкиВзаимодействий.РассмотретьПосле) КАК РассмотретьПосле
ИЗ
Справочник.Запросы КАК СправочникЗапросы
ЛЕВОЕ СОЕДИНЕНИЕ Документ.ТелефонныйЗвонок КАК ТелефонныйЗвонок
ПО СправочникЗапросы.Ссылка = ТелефонныйЗвонок.ВзаимодействиеОснование
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК ПредметыПапкиВзаимодействий
ПО (ТелефонныйЗвонок.Ссылка = ПредметыПапкиВзаимодействий.Взаимодействие)
ГРУППИРОВАТЬ ПО
СправочникЗапросы.Наименование,
СправочникЗапросы.ВидЗапроса,
СправочникЗапросы.ДатаСоздания,
СправочникЗапросы.Имя,
СправочникЗапросы.Источник,
ВЫРАЗИТЬ(СправочникЗапросы.Описание КАК СТРОКА(1000)),
СправочникЗапросы.Ответственный,
СправочникЗапросы.РегионКлиента,
СправочникЗапросы.Статус,
СправочникЗапросы.Телефон,
СправочникЗапросы.ЭлектроннаяПочта,
СправочникЗапросы.Ссылка
В данном случае использование МАКСИМУМ для полей Рассмотрено и РассмотретьПосле позволяет «схлопнуть» несколько звонков в одну строку динамического списка. Система выберет значения из последнего (по алфавиту или ссылке) документа.
Хотя первый вариант работает, он может быть медленным на больших объемах данных из-за группировки по всем полям. Проанализируем более профессиональный подход: получение среза данных во вложенном запросе. Это позволит динамическому списку работать быстрее и корректнее определять Основную таблицу.
Разберем логику: нам нужно сначала найти для каждого запроса один-единственный звонок, а уже потом присоединять его данные. Это гарантирует связь 1-к-1.
ВЫБРАТЬ
СправочникЗапросы.Ссылка КАК Ссылка,
СправочникЗапросы.Наименование,
СправочникЗапросы.ДатаСоздания,
ПоследнийЗвонок.СсылкаДокумент,
Рег.Рассмотрено,
Рег.РассмотретьПосле
ИЗ
Справочник.Запросы КАК СправочникЗапросы
ЛЕВОЕ СОЕДИНЕНИЕ (
ВЫБРАТЬ
ТелефонныйЗвонок.ВзаимодействиеОснование КАК Предмет,
МАКСИМУМ(ТелефонныйЗвонок.Ссылка) КАК СсылкаДокумент
ИЗ
Документ.ТелефонныйЗвонок КАК ТелефонныйЗвонок
ГРУППИРОВАТЬ ПО
ТелефонныйЗвонок.ВзаимодействиеОснование
) КАК ПоследнийЗвонок ПО СправочникЗапросы.Ссылка = ПоследнийЗвонок.Предмет
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ПредметыПапкиВзаимодействий КАК Рег
ПО ПоследнийЗвонок.СсылкаДокумент = Рег.Взаимодействие
Преимущества этого метода:
ГРУППИРОВАТЬ ПО, что облегчает работу механизмов компоновки данных.При написании таких запросов часто возникают ошибки, которые стоит рассмотреть подробнее:
ПО следует за другим), область видимости псевдонимов может нарушаться. Рекомендуется использовать плоскую структуру соединений.СправочникЗапросы.Ссылка = ТелефонныйЗвонок.ВзаимодействиеОснование. В типовых конфигурациях 1С (БСП) поле ВзаимодействиеОснование может не заполняться автоматически при создании звонка «на основании». Иногда связь нужно устанавливать через реквизит Предмет или использовать регистр сведений КонтактыВзаимодействий. Обязательно проверьте типы данных в конфигураторе.DISTINCT (Различные) заставляет сервер БД сравнивать все поля во всех строках. Если в списке есть длинные строки (неограниченной длины), их необходимо приводить к фиксированной длине через ВЫРАЗИТЬ(Поле КАК СТРОКА(1000)), иначе запрос выдаст ошибку.Для обеспечения максимальной производительности придерживайтесь следующих правил:
Запросы и его обновления при проведении звонка. Чтение из одной таблицы всегда быстрее, чем сложные соединения.Рассмотренные способы помогут вам создавать отзывчивые и информативные интерфейсы в 1С, обеспечивая пользователей актуальными данными без лишнего визуального шума в виде дублирующихся записей.