При разработке отчетов, печатных форм или обработок в «1С:Предприятие 8.3» программисты часто сталкиваются с задачей получения контактной информации контрагентов или собственных организаций. На первый взгляд задача кажется тривиальной: написать запрос к источнику данных и вывести результат. Однако при работе с современными конфигурациями, построенными на базе Библиотеки стандартных подсистем (БСП), такими как «Бухгалтерия для Казахстана 3.0» или «Бухгалтерия предприятия 3.0», разработчики часто совершают типичные ошибки, из-за которых запросы возвращают пустой результат.
В этой статье мы подробно проанализируем, почему стандартные запросы к регистру сведений КонтактнаяИнформация перестают работать, разберем ключевые ошибки в логике построения запросов и рассмотрим два наиболее эффективных способа решения этой проблемы: с помощью исправленного SQL-подобного запроса 1С и через использование готового программного интерфейса БСП.
Давайте выясним, почему старые методы запросов к контактной информации не работают в новых редакциях конфигураций. В устаревших версиях систем (например, в «Бухгалтерии 2.0») контактная информация физических лиц, контрагентов и организаций действительно хранилась в независимом регистре сведений РегистрСведений.КонтактнаяИнформация.
В современных конфигурациях редакции 3.0 архитектура хранения данных кардинально изменилась:
КонтактнаяИнформация справочника Организации (то есть Справочник.Организации.КонтактнаяИнформация). Сам регистр сведений может физически присутствовать в структуре метаданных для обеспечения обратной совместимости, но он либо пуст, либо не обновляется.Поле1, Поле2 ... Поле9). Теперь детальные поля адреса упаковываются в одну строку в формате XML или JSON и записываются в поле ЗначенияПолей. В запросе разобрать эту строку невозможно. Строковое представление адреса целиком хранится в поле Представление.Таким образом, пытаясь обратиться напрямую к регистру сведений РегистрСведений.КонтактнаяИнформация и выбирая поля Поле4 или Поле6, мы гарантированно получим либо пустой результат, либо некорректные данные.
---
Проанализируем программный код, который был представлен в начале обсуждения, и укажем на критические ошибки, которые не позволяли запросу отработать правильно.
Ошибка первая: Сравнение ссылки с наименованием в параметрах.
В исходном запросе мы видим условие:
КонтактнаяИнформация.Вид.Наименование = &ЮридическийВид
При этом в коде параметр устанавливается следующим образом:
Запрос.УстановитьПараметр("ЮридическийВид", Справочники.ВидыКонтактнойИнформации.НайтиПоНаименованию("Юридический адрес организации"));
Функция НайтиПоНаименованию() возвращает Ссылка на элемент справочника ВидыКонтактнойИнформации. В результате в запросе происходило сравнение строки (наименования вида) со ссылкой на элемент справочника. Такое условие никогда не выполнится, и запрос вернет пустую выборку. Правильно сравнивать ссылки напрямую: КонтактнаяИнформация.Вид = &ЮридическийВид.
Ошибка вторая: Некорректное соединение таблиц (Декартово произведение).
Посмотрим на конструкцию связи таблиц во ИЗ:
ИЗ
РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации КАК Организации
ПО КонтактнаяИнформация.Объект = Организации.Ссылка,
(ВЫБРАТЬ ... ) КАК Юр
Использование запятой перед вложенным запросом Юр без указания явного условия соединения (ПО) приводит к полному (декартову) произведению таблиц. Это сильно снижает производительность СУБД. Более того, жесткие фильтры в секции ГДЕ для левой и правой таблиц приводят к тому, что если у организации отсутствует хотя бы один из видов адреса (например, нет фактического), то запрос не вернет вообще ничего — пропадет даже юридический адрес.
---
Разработчики БСП настоятельно рекомендуют отказаться от написания прямых запросов к табличным частям для получения контактной информации. Для этого в системе предусмотрены готовые, оптимизированные функции общего модуля УправлениеКонтактнойИнформацией.
Рассмотрим, как получить представления юридического и фактического адресов организации программным путем без написания сложных запросов. Это наиболее надежный метод, который защитит ваш код от возможных изменений структуры метаданных в будущих обновлениях платформы.
// Определим организацию, по которой нужно получить данные
ОрганизацияСсылка = Справочники.Организации.НайтиПоРеквизиту("БИН", "123456789012"); // Пример поиска
Если ЗначениеЗаполнено(ОрганизацияСсылка) Тогда
// Получаем виды контактной информации (предопределенные элементы справочника)
ВидФактический = Справочники.ВидыКонтактнойИнформации.ФактАдресОрганизации;
ВидЮридический = Справочники.ВидыКонтактнойИнформации.ЮрАдресОрганизации;
// Получаем фактический адрес организации в виде строки
ФактическийАдресСтрокой = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(
ОрганизацияСсылка,
ВидФактический
);
// Получаем юридический адрес организации в виде строки
ЮридическийАдресСтрокой = УправлениеКонтактнойИнформацией.КонтактнаяИнформацияОбъекта(
ОрганизацияСсылка,
ВидЮридический
);
// Выводим результат для проверки
Сообщить("Фактический адрес: " + ФактическийАдресСтрокой);
Сообщить("Юридический адрес: " + ЮридическийАдресСтрокой);
КонецЕсли;
Этот способ крайне прост в сопровождении. Функция КонтактнаяИнформацияОбъекта самостоятельно определяет актуальное место хранения данных, корректно считывает XML/JSON структуру и возвращает готовое текстовое представление адреса.
---
Если вам все же необходимо получить адреса именно через запрос (например, для использования в схеме компоновки данных (СКД), динамическом списке или сложном отчете), мы должны переписать его структуру с нуля.
Давайте пошагово разберем логику построения правильного запроса:
Организации.ЛЕВОЕ СОЕДИНЕНИЕ с табличной частью Организации.КонтактнаяИнформация. Условием связи будет равенство ссылок организации и ограничение по виду КИ (фактический адрес).ЛЕВОЕ СОЕДИНЕНИЕ с этой же табличной частью организации, но уже с фильтром по юридическому виду КИ.ЛЕВОГО СОЕДИНЕНИЯ гарантирует нам, что даже если один из адресов не заполнен, система все равно вернет саму организацию и тот адрес, который заполнен.Ниже представлен готовый программный код с исправленным и оптимизированным запросом:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Организации.Ссылка КАК Организация,
| ЕСТЬNULL(АдресФактический.Представление, """") КАК ФактАдрес,
| ЕСТЬNULL(АдресЮридический.Представление, """") КАК ЮрАдрес
|ИЗ
| Справочник.Организации КАК Организации
|
| // Присоединяем фактический адрес организации
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации.КонтактнаяИнформация КАК АдресФактический
| ПО АдресФактический.Ссылка = Организации.Ссылка
| И АдресФактический.Вид = &ВидФактический
|
| // Присоединяем юридический адрес организации
| ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Организации.КонтактнаяИнформация КАК АдресЮридический
| ПО АдресЮридический.Ссылка = Организации.Ссылка
| И АдресЮридический.Вид = &ВидЮридический
|ГДЕ
| Организации.Ссылка = &Организация";
// Передаем параметры в запрос.
// Используем предопределенные элементы видов КИ, чтобы избежать поиска по наименованию.
Запрос.УстановитьПараметр("Организация", ВыбраннаяОрганизация);
Запрос.УстановитьПараметр("ВидФактический", Справочники.ВидыКонтактнойИнформации.ФактАдресОрганизации);
Запрос.УстановитьПараметр("ВидЮридический", Справочники.ВидыКонтактнойИнформации.ЮрАдресОрганизации);
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
// Теперь мы гарантированно получаем строковые адреса без пустых строк
ЮрАдрес = Выборка.ЮрАдрес;
ФактАдрес = Выборка.ФактАдрес;
// Дальнейшая обработка адресов...
КонецЦикла;
Обратите внимание на использование функции ЕСТЬNULL в запросе. Если у организации не окажется заполненного фактического или юридического адреса, СУБД вернет значение NULL. Функция ЕСТЬNULL(..., "") автоматически заменяет NULL на пустую строку, что предотвращает возникновение ошибок типов при дальнейшей работе с данными в коде.
Также важным изменением является отказ от поиска видов адресов по наименованию в коде. В типовых конфигурациях 1С виды контактной информации являются предопределенными элементами. Конструкция вида Справочники.ВидыКонтактнойИнформации.ЮрАдресОрганизации работает быстрее и надежнее, так как наименование элемента в пользовательском режиме может быть изменено бухгалтером, а предопределенное имя (идентификатор) в конфигураторе остается неизменным.