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