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

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

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

Причина 1: Транзакционная изоляция и состояние данных

Главное различие между выполнением запроса в консоли и в процедуре ОбработкаПроведения заключается в контексте транзакции. Когда мы запускаем запрос в консоли, мы читаем данные, которые уже зафиксированы в базе данных (режим Read Committed). В момент проведения ситуация иная. Рассмотрим, что происходит внутри транзакции:

  1. Данные объекта не записаны в БД: Если в коде перед вызовом запроса данные табличной части документа были изменены, но метод Записать() не был вызван, SQL-сервер при выполнении запроса к таблицам документа увидит их старое состояние.
  2. Движения в регистрах: Если запрос обращается к регистру сведений, по которому этот же документ делает движения, результат будет зависеть от того, записаны ли уже движения. В типовых механизмах проведение часто идет сначала "по памяти", а физическая запись в таблицы движений происходит позже.

Проанализируем фрагмент запроса, предоставленный автором темы, который формирует временную таблицу (или вложенный запрос):


ВЫБРАТЬ 
    ТЧРаботникиОрганизации.НомерСтроки КАК НомерСтроки, 
    МАКСИМУМ(Работники.Период) КАК Период, 
    ТЧРаботникиОрганизации.Сотрудник КАК Сотрудник 
ИЗ 
    Документ.КадровоеПеремещениеОрганизаций.РаботникиОрганизации КАК ТЧРаботникиОрганизации 
ВНУТРЕННЕЕ СОЕДИНЕНИЕ 
    РегистрСведений.РаботникиОрганизаций КАК Работники 
ПО 
    (Работники.Период <= ТЧРаботникиОрганизации.ДатаНачала) 
    И ТЧРаботникиОрганизации.Сотрудник = Работники.Сотрудник 
ГДЕ 
    ТЧРаботникиОрганизации.Ссылка = &ДокументСсылка 
СГРУППИРОВАТЬ ПО 
    ТЧРаботникиОрганизации.НомерСтроки, 
    ТЧРаботникиОрганизации.Сотрудник

Если в консоли этот запрос выдает данные, а в коде — NULL, это означает, что ВНУТРЕННЕЕ СОЕДИНЕНИЕ (Inner Join) не находит соответствий. Это происходит, если в регистре РаботникиОрганизаций еще нет записей по данному сотруднику на указанную дату, либо ссылка на документ &ДокументСсылка в контексте базы данных еще не содержит обновленной табличной части.

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

Часто ошибка кроется в нюансах передачи параметров. В консоли мы выбираем значения интерактивно, а в коде они могут принимать значения Неопределено или NULL незаметно для разработчика. Проанализируем типичные ошибки:

Причина 3: Механизм RLS (Разграничение прав доступа)

В тексте запроса используется ключевое слово РАЗРЕШЕННЫЕ. Это крайне важный момент. Выясним причину возможного расхождения:

Если программист запускает консоль под полными правами, а проведение документа тестируется под пользователем с ограниченными правами, система RLS автоматически добавит в запрос скрытые условия. Если пользователю запрещено чтение определенных подразделений или организаций, ВНУТРЕННЕЕ СОЕДИНЕНИЕ просто отсечет эти строки, и итоговая таблица будет пустой. При использовании ЛЕВОЕ СОЕДИНЕНИЕ в основном запросе все поля присоединенной таблицы станут NULL.

Причина 4: Использование виртуальных таблиц и построителя

Автор упоминает, что "ошибочное значение в виртуальной таблице, которая видна в конструкторе только на вкладке 'построитель'". Это указывает на то, что запрос может использовать механизмы автозаполнения полей или параметров. В 1С 8.2 построитель отчетов/запросов может добавлять свои условия на дату актуальности или параметры виртуальных таблиц. Посмотрим на сложную структуру соединений в основном запросе:


ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ 
        ДатыПоследнихДвиженийРаботников.НомерСтроки КАК НомерСтроки, 
        ...
    ИЗ (
        ВЫБРАТЬ 
            ТЧРаботникиОрганизации.НомерСтроки КАК НомерСтроки, 
            МАКСИМУМ(Работники.Период) КАК Период
        ИЗ ...
    ) КАК ДатыПоследнихДвиженийРаботников
) КАК ДанныеПоРаботникуДоНазначения 
ПО ТЧРаботникиОрганизации.НомерСтроки = ДанныеПоРаботникуДоНазначения.НомерСтроки

Когда мы соединяем результат сложного вложенного запроса через ЛЕВОЕ СОЕДИНЕНИЕ, любая ошибка в условиях внутреннего фильтра (например, в подзапросе ДатыПоследнихДвиженийРаботников) приведет к тому, что все поля превратятся в NULL. В консоли вы можете не заметить отсутствие одной строки, а в алгоритме проведения это вызовет сбой бизнес-логики.

Как гарантированно найти ошибку: пошаговый алгоритм

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

  1. Проверка параметров в отладке: Перед выполнением запроса в коде поставьте точку останова. Убедитесь, что Запрос.Параметры содержит именно те значения, которые вы вводите в консоли. Особое внимание уделите объекту Ссылка — она должна быть записана в базу.
  2. Выгрузка промежуточных данных: Разделите один огромный запрос на несколько. Выгрузите результат проблемного вложенного запроса в таблицу значений прямо в коде: ТЗ = Запрос.Выполнить().Выгрузить();. Посмотрите в отладчике, сколько там строк. Если 0 — значит, проблема во внутреннем INNER JOIN или RLS.
  3. Тест без "РАЗРЕШЕННЫЕ": Попробуйте временно убрать это слово из запроса в модуле проведения. Если данные появятся — проблема в настройках прав доступа.
  4. Принудительная запись: Если документ является регистратором для регистра, из которого вы тянете данные, попробуйте перед запросом вызвать ЭтотОбъект.Записать() или даже временно записать движения в набор записей с установкой Записывать = Истина.

Важный итог: Появление NULL в модуле проведения при наличии данных в консоли — это почти всегда признак того, что запрос "не видит" записи в физических таблицах базы данных из-за контекста транзакции или неверно переданных ссылочных параметров.

← На главную