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

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

Разработка в среде 1С:Предприятие часто преподносит сюрпризы, когда один и тот же запрос, успешно протестированный в интерактивной консоли, отказывается выдавать данные при выполнении в программном модуле. Это классическая ситуация, через которую проходит каждый начинающий разработчик. В этой статье мы детально проанализируем причины такого поведения, разберем технические нюансы работы с параметрами и выясним, как избежать подобных ошибок в будущем.

Различие в типах данных: Ловушка параметра ДанныеЗаполнения

Одной из самых частых причин расхождения результатов является неявная типизация. Рассмотрим ситуацию, описанную в сообщениях форума. Разработчик использует переменную ДанныеЗаполнения в качестве параметра запроса. В контексте процедуры ОбработкаЗаполнения этот объект может принимать совершенно разные формы в зависимости от способа создания документа.

Проанализируем возможные типы переменной ДанныеЗаполнения:

  1. Ссылка на объект: Если документ создается командой «Создать на основании», платформа передает ссылку на документ-источник. В этом случае запрос отработает корректно.
  2. Структура: Если документ создается программно или через механизм заполнения из списка с множественным выбором, в ДанныеЗаполнения попадает объект типа Структура.
  3. Неопределено: При простом создании нового документа.

В консоли запросов программист всегда выбирает конкретную ссылку интерактивно. В коде же, передавая ДанныеЗаполнения без проверки типа, мы рискуем отправить в запрос Структуру. С точки зрения SQL-сервера, сравнение ссылки (GUID) со структурой (которая для него является бессмысленным набором данных) всегда будет ложным (FALSE). В итоге запрос выполняется без ошибок, но возвращает пустой результат.

Для исправления ситуации необходимо всегда проверять тип передаваемого параметра:


Если ТипЗнч(ДанныеЗаполнения) = Тип("ДокументСсылка.ЗаказПокупателя") Тогда
    Запрос.УстановитьПараметр("Ссылка", ДанныеЗаполнения);
ИначеЕсли ТипЗнч(ДанныеЗаполнения) = Тип("Структура") И ДанныеЗаполнения.Свойство("ДокументОснование") Тогда
    Запрос.УстановитьПараметр("Ссылка", ДанныеЗаполнения.ДокументОснование);
КонецЕсли;

Избыточное разыменование полей или ошибка через точку

Обратим внимание на текст запроса во втором сообщении: ГДЕ СписаниеЗапасов.ДокументОснование.Ссылка = &Ссылка. Здесь кроется вторая серьезная методическая ошибка. Поле ДокументОснование само по себе уже является ссылкой.

Рассмотрим, что происходит «под капотом» платформы при обращении через точку к полю Ссылка:

  1. Платформа видит обращение к реквизиту связанной таблицы (даже если этот реквизит — сама Ссылка).
  2. В SQL-запрос добавляется неявное левое соединение (LEFT JOIN) с таблицей документа основания.
  3. Это приводит к снижению производительности, так как СУБД приходится выполнять лишнюю операцию соединения таблиц.

Правильный и наиболее эффективный вариант написания условия выглядит так:


Запрос.Текст = 
    "ВЫБРАТЬ
    |	СписаниеЗапасов.Ссылка КАК Ссылка
    |ИЗ
    |	Документ.СписаниеЗапасов КАК СписаниеЗапасов
    |ГДЕ
    |	СписаниеЗапасов.ДокументОснование = &Ссылка";

В данном случае сравнение идет напрямую со значением в физической таблице СписаниеЗапасов, без привлечения данных из других таблиц.

Человеческий фактор: Разные запросы — разные результаты

Как справедливо заметили участники обсуждения в сообщении №9, часто проблема кроется в банальной невнимательности. В первом варианте (для консоли) автор использовал фильтр по полю Корреспонденция, а в программном коде — по полю ДокументОснование.

Выясним причину, почему это критично:

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

Влияние прав доступа (RLS)

Проанализируем еще один важный аспект: контекст выполнения. Консоль запросов часто запускается администратором или пользователем с полными правами. Программный же код выполняется под правами текущего пользователя.

Если в системе настроены Ограничения доступа на уровне записей (RLS), то запрос может вести себя следующим образом:

Для диагностики этой проблемы попробуйте выполнить тот же запрос в коде, обернув его в привилегированный режим, или проверьте права пользователя на чтение документа СписаниеЗапасов и всех документов, входящих в состав типа ДокументОснование.

Итоги и рекомендации

Подводя итог, разберем по шагам алгоритм действий, если ваш запрос «сломался» при переносе в код:

  1. Проверьте параметры: Используйте отладчик, чтобы убедиться, что в Запрос.УстановитьПараметр передается именно Ссылка, а не Структура, Строка или Число.
  2. Очистите текст запроса: Удалите лишние обращения через точку (разыменования), такие как .Ссылка. Сравнивайте ссылочные поля напрямую.
  3. Синхронизируйте тексты: Убедитесь, что условия ГДЕ в консоли и в коде идентичны. Обратите внимание на использование параметров (например, не перепутаны ли &Ссылка и &Документ).
  4. Учитывайте контекст: Помните про RLS и транзакции. Если данные только что были созданы в коде и еще не записаны (или не зафиксированы транзакцией), внешний запрос в консоли их не увидит, а запрос внутри той же транзакции — увидит.

Соблюдение этих простых правил позволит вам быстро находить ошибки в запросах и писать более качественный и производительный код в системе 1С:Предприятие.

← На главную