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