Почему один и тот же запрос работает в Консоли запросов, но возвращает ошибку или пустой результат в коде 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Каждый разработчик на платформе 1С:Предприятие рано или поздно сталкивается с парадоксальной ситуацией: написанный запрос идеально отрабатывает в Консоли запросов, выводя нужные строки, но при запуске того же самого кода в конфигурации программа либо выдает «ошибку чтения», либо возвращает пустой результат.

В этой статье мы подробно разберем, почему возникает такое поведение, проанализируем ключевые причины и покажем, как шаг за шагом исправить логику работы программы.

Причина 1. Ограничение доступа на уровне записей (RLS) и права пользователей

Это наиболее распространенная причина расхождения результатов. Разберем ситуацию детально. Консоль запросов разработчик почти всегда запускает под учетной записью с «Полными правами». В этом режиме платформа полностью игнорирует любые ограничения прав доступа. Напротив, в режиме отладки или при работе пользователя сеанс может быть запущен под учетной записью с ограниченными правами (например, менеджер по продажам или бухгалтер), у которой настроен механизм RLS (Row-Level Security) по организациям, складам или контрагентам.

Если в коде выполняется запрос к таблице, на которую у пользователя наложены ограничения прав, система поведет себя следующим образом:

  1. Если в тексте запроса указано просто ВЫБРАТЬ, а у пользователя нет прав на чтение определенных записей (или всей таблицы), платформа выбросит исключение «Ошибка чтения» или «Нарушение прав доступа».
  2. Если в консоли запрос выполнялся под администратором, никакой ошибки не возникнет, и данные будут успешно прочитаны.

Для исправления этого поведения проанализируем два пути решения:

Способ А. Использование ключевого слова РАЗРЕШЕННЫЕ

Добавление конструкции РАЗРЕШЕННЫЕ указывает платформе, что из базы данных нужно выбрать только те записи, на чтение которых у текущего пользователя есть права. Ошибка чтения при этом исчезнет, а запрос вернет только доступные данные.

Посмотрим на пример измененного текста запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |    Продажи.Количество,
    |    Продажи.Стоимость,
    |    Продажи.НДС
    |ИЗ
    |    РегистрНакопления.Продажи КАК Продажи
    |ГДЕ
    |    Продажи.Период МЕЖДУ &ДатаНач И &ДатаКон";

Способ Б. Выполнение кода в привилегированном режиме

Если бизнес-логика требует, чтобы запрос гарантированно прочитал все данные (например, при проведении документа или расчете себестоимости на сервере), выполнение кода необходимо временно перевести в привилегированный режим. В этом случае RLS будет временно отключен.

Для этого воспользуемся методом УстановитьПривилегированныйРежим:


УстановитьПривилегированныйРежим(Истина);

Запрос = Новый Запрос;
// Настройка параметров и выполнение запроса...
РезультатЗапроса = Запрос.Выполнить();

УстановитьПривилегированныйРежим(Ложь);

Причина 2. Тонкости передачи параметров и неявные типы данных

При работе в Консоли запросов разработчик заполняет параметры интерактивно: выбирает конкретный элемент из справочника или вводит точную дату в календаре. В программном коде параметры передаются динамически из переменных, реквизитов формы или строк табличных частей, что таит в себе скрытые ловушки.

Несохраненные объекты (Ссылки нового)

Представим ситуацию, когда в качестве параметра &ДоговорКонтрагента передается ссылка из только что созданного на форме договора. Если объект еще не был физически записан в базу данных, ссылка на него уже существует в памяти (так называемая «Ссылка нового»), но в таблицах базы данных СУБД такой записи еще нет. Запрос вернет пустой результат, в то время как в консоли вы гарантированно выбирали уже сохраненный в базе договор.

Проблемы с границами дат

В консоли разработчик интуитивно может выставить дату конца периода как 31.12.2023 23:59:59. В коде же значение ДоговорКонтрагента.СрокДействия часто хранится без времени (значение времени по умолчанию равно 00:00:00).

Если в коде написать:

Запрос.УстановитьПараметр("ДатаКон", ДоговорКонтрагента.СрокДействия);

То все продажи, совершенные в день окончания договора после полуночи (например, в 12:00 дня), в результат запроса не попадут, так как условие МЕЖДУ ограничит выборку началом этого дня. Для решения этой проблемы рекомендуется использовать функцию КонецДня:

Запрос.УстановитьПараметр("ДатаКон", КонецДня(ДоговорКонтрагента.СрокДействия));

Значения Неопределено и NULL

В коде параметр может принять значение Неопределено или Null (например, если строка таблицы НайденнаяСтрока.Номенклатура оказалась пустой). При отладке обязательно проверяйте типы передаваемых параметров с помощью Табло или Вычисления выражения.

Причина 3. Обращение к физической таблице регистра вместо виртуальной

В исходном коде автора запроса выборка данных происходит напрямую из физической таблицы РегистрНакопления.Продажи:


ИЗ
    РегистрНакопления.Продажи КАК Продажи
ГДЕ
    Продажи.Период МЕЖДУ &ДатаНач И &ДатаКон
    И Продажи.Номенклатура = &Номенклатура

Это грубейшая ошибка проектирования запросов в 1С. Прямое обращение к физической таблице заставляет СУБД сканировать весь массив записей регистра. На копии базы или в консоли при отсутствии нагрузки это может работать быстро, но в реальной многопользовательской среде такой запрос приведет к избыточным блокировкам таблиц и ошибкам чтения (таймаутам блокировок).

Для исправления этой архитектурной проблемы всегда используйте виртуальные таблицы оборотов или остатков. Намного эффективнее передавать параметры отбора напрямую в параметры виртуальной таблицы:


Запрос.Текст = 
    "ВЫБРАТЬ РАЗРЕШЕННЫЕ
    |    ПродажиОбороты.КоличествоОборот КАК Количество,
    |    ПродажиОбороты.СтоимостьОборот КАК Стоимость,
    |    ПродажиОбороты.НДСОборот КАК НДС
    |ИЗ
    |    РегистрНакопления.Продажи.Обороты(&ДатаНач, &ДатаКон, , Номенклатура = &Номенклатура И ДоговорКонтрагента = &ДоговорКонтрагента) КАК ПродажиОбороты";

Этот подход позволяет платформе 1С построить оптимальный SQL-запрос, который обратится к предварительно рассчитанным итогам СУБД, что ускорит выполнение операции в десятки раз и предотвратит ошибки чтения под нагрузкой.

Причина 4. Кэширование платформы и внешних обработок

Иногда код работает некорректно из-за устаревшего локального кэша метаданных. Особенно часто это проявляется при разработке внешних обработок. Если обработка аварийно завершила работу или была изменена в конфигураторе, платформа 1С может продолжать запускать старую версию обработки из временной папки кэша приложений.

Рекомендуется выполнить следующие действия:

Используя приведенные методики, мы гарантируем стабильное выполнение запросов в кодовой среде конфигурации, полностью соответствующее результатам тестирования в Консоли запросов.

← На главную