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