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

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

В практике разработчика 1С нередко встречается парадоксальная ситуация: один и тот же текст запроса, запущенный в консоли запросов, выводит корректные данные, но при попытке выполнить его программно (например, во внешней печатной форме или обработке) результат оказывается пустым. Особенно часто это проявляется при работе с документами в конфигурации Зарплата и управление персоналом 3.1, например, с документом РазовоеНачисление.

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

Причина 1: Неявные соединения при обращении через точку

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


ВЫБРАТЬ
    РазовоеНачисление.Начисления.Сотрудник КАК Сотрудник,
    РазовоеНачисление.Начисления.Результат КАК Компенсация
ИЗ
    Документ.РазовоеНачисление КАК РазовоеНачисление

Проанализируем этот код. Когда мы пишем РазовоеНачисление.Начисления.Сотрудник, платформа 1С пытается выполнить неявное соединение основной таблицы документа с его табличной частью. Консоль запросов часто интерпретирует такие конструкции более "либерально", подстраивая план выполнения под текущий контекст. Однако при программном выполнении, особенно в сложных условиях (например, внутри циклов или во внешних модулях), такая структура запроса может привести к некорректному результату или пустому набору данных.

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

Причина 2: Проблема поиска по коду и передачи параметров

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


Начисление = ПланыВидовРасчета.Начисления.НайтиПоКоду("ВППУ ");
ЗапросНачисление.УстановитьПараметр("Начисление", Начисление.Ссылка);

Обратите внимание на строку "ВППУ ". В 1С коды часто имеют фиксированную длину. Если в базе код записан с пробелом на конце, а в коде вы его не укажете (или наоборот), метод НайтиПоКоду() вернет ПустаяСсылка. В консоли запросов вы выбираете параметр интерактивно, поэтому запрос работает. В программном коде же передается пустая ссылка, и условие ГДЕ отсекает все записи.

Также стоит помнить, что обращение к свойству .Ссылка у переменной, которая уже является ссылкой (результат НайтиПоКоду), избыточно. Это не ошибка, но излишнее загромождение кода.

Причина 3: Запрос в цикле — критическая ошибка производительности

Проанализируем ситуацию, когда запрос выполняется внутри цикла обхода другой выборки. Это классическая ошибка "Запрос в цикле", которая крайне негативно сказывается на скорости работы системы. Рассмотрим, как переписать такой код правильно.

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

Оптимальное решение проблемы

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

Шаг 1. Подготовка параметров. Сначала соберем массив ссылок сотрудников, по которым нам нужны данные.


МассивСотрудников = Новый Массив;
Пока ВыборкаИзПервогоЗапроса.Следующий() Цикл
    МассивСотрудников.Добавить(ВыборкаИзПервогоЗапроса.Сотрудник);
КонецЦикла;

Шаг 2. Написание правильного запроса. Обращаемся напрямую к таблице Документ.РазовоеНачисление.Начисления.


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

// Проверяем корректность поиска начисления
ВидНачисления = ПланыВидовРасчета.Начисления.НайтиПоКоду("ВППУ ");
Если ВидНачисления.Пустая() Тогда
    Сообщить("Внимание: Начисление с кодом 'ВППУ ' не найдено в базе!");
КонецЕсли;

Запрос.УстановитьПараметр("МассивСотрудников", МассивСотрудников);
Запрос.УстановитьПараметр("Начисление", ВидНачисления);

Выборка = Запрос.Выполнить().Выбрать();

Дополнительные факторы: Права доступа и Безопасный режим

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

  1. Использование ключевого слова РАЗРЕШЕННЫЕ. В программном коде, если у пользователя настроены ограничения на уровне записей (RLS), запрос без РАЗРЕШЕННЫЕ может вызывать ошибку прав или возвращать пустой результат. Консоли запросов часто запускаются под полными правами или в привилегированном режиме, что скрывает эту проблему.
  2. Безопасный режим во внешних формах. Внешние печатные формы часто подключаются в безопасном режиме. Это может ограничивать доступ к некоторым объектам метаданных или методам. Попробуйте протестировать код, встроив его непосредственно в конфигурацию или временно отключив безопасный режим при регистрации обработки.

Резюме: Чтобы ваш запрос работал стабильно, всегда используйте прямые обращения к табличным частям (Документ.ИмяДокумента.ИмяТабличнойЧасти), проверяйте результаты поиска параметров (НайтиПоКоду) на пустоту и избегайте выполнения запросов внутри циклов. Такой подход гарантирует идентичность работы кода как в консоли, так и в реальной эксплуатации.

← На главную