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