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