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