При работе со сложными запросами в 1С:Предприятии программисты часто сталкиваются с ситуацией, когда один и тот же код ведет себя по-разному в контексте исполнения конфигурации и в консоли запросов. Особенно это актуально для метода ВыполнитьПакетСПромежуточнымиДанными, который предназначен для облегчения отладки пакетных запросов, позволяя просматривать содержимое каждой временной таблицы. Разберем подробно, почему возникают такие расхождения и как правильно диагностировать проблему.
Метод ВыполнитьПакетСПромежуточнымиДанными появился в платформе 8.3.10 и стал незаменимым инструментом. В отличие от стандартного ВыполнитьПакет, который возвращает массив результатов только для инструкций ВЫБРАТЬ, новый метод возвращает результаты для всех частей пакета, включая те, где данные помещаются во временные таблицы (ПОМЕСТИТЬ).
Проанализируем типичную ситуацию: в коде программы вы выполняете пакетный запрос, и при проверке в табло отладчика таблица, которая должна содержать данные, оказывается пустой. Однако, стоит перенести текст запроса в консоль и подставить те же параметры, как данные чудесным образом появляются. Рассмотрим основные причины этого феномена.
Первая и самая частая причина — неявное различие в типах передаваемых параметров. В коде конфигурации параметр может иметь тип ДокументОбъект, в то время как запрос ожидает ДокументСсылка. Хотя 1С часто выполняет автоматическое приведение типов, при работе с временными таблицами и левыми соединениями это может привести к тому, что условие связи ПО не сработает.
Рассмотрим пример запроса из обсуждения:
ВЫБРАТЬ &ДокОтгрузки КАК Ссылка
ПОМЕСТИТЬ ВТ_ДокументыОтгрузки ;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ РАЗЛИЧНЫЕ
ЕСТЬNULL(ХозрасчетныйСубконто.Значение, НЕОПРЕДЕЛЕНО) КАК Партия
ПОМЕСТИТЬ ВТ_Партии
ИЗ ВТ_ДокументыОтгрузки КАК ВТ_ДокументыОтгрузки
ЛЕВОЕ СОЕДИНЕНИЕ РегистрБухгалтерии.Хозрасчетный.Субконто КАК ХозрасчетныйСубконто
ПО ВТ_ДокументыОтгрузки.Ссылка = ХозрасчетныйСубконто.Регистратор
И (ХозрасчетныйСубконто.ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияБухгалтерии.Кредит))
И (ХозрасчетныйСубконто.Вид = ЗНАЧЕНИЕ(ПланВидовХарактеристик.ВидыСубконтоХозрасчетные.Партии))
ИНДЕКСИРОВАТЬ ПО Партия ;
Для исключения ошибок типизации в первой части пакета рекомендуется использовать явное приведение типа через функцию ВЫРАЗИТЬ или обращение к реальной таблице базы данных. Посмотрим на два варианта исправления:
ВЫБРАТЬ ВЫРАЗИТЬ(&ДокОтгрузки КАК Документ.РеализацияТоваровУслуг) КАК Ссылка ПОМЕСТИТЬ ВТ_ДокументыОтгрузки
ВЫБРАТЬ таблица.Ссылка КАК Ссылка ПОМЕСТИТЬ ВТ_ДокументыОтгрузки ИЗ Документ.РеализацияТоваровУслуг КАК таблица ГДЕ таблица.Ссылка = &ДокОтгрузки
Чтобы исключить влияние человеческого фактора при ручном заполнении параметров в консоли, воспользуемся методом выгрузки запроса в XML. В современных конфигурациях на базе БСП (Библиотеки стандартных подсистем) существует функция, позволяющая получить полную структуру запроса со всеми установленными значениями параметров.
Проанализируем шаги для точной отладки:
ОбщегоНазначения.ЗапросВСтрокуXML(Запрос)
Этот метод гарантирует, что в консоль попадут ровно те же значения ссылок, моментов времени и перечислений, которые используются в текущем сеансе отладки. Если после этого запрос в консоли вернет данные, а в коде через ВыполнитьПакетСПромежуточнымиДанными — нет, значит причина кроется в особенностях платформы или транзакционных блокировках.
Метод ВыполнитьПакетСПромежуточнымиДанными часто запускается внутри транзакции проведения документа. В этот момент данные в регистре (например, РегистрБухгалтерии.Хозрасчетный.Субконто) могут быть уже изменены или помечены к удалению, но еще не зафиксированы. Консоль запросов, запущенная параллельно, работает в другом сеансе и может не видеть "грязных" данных текущей транзакции.
Также не стоит забывать про RLS (Record Level Security). В коде запрос выполняется от имени пользователя с ограниченными правами. Метод ВыполнитьПакетСПромежуточнымиДанными честно учитывает эти ограничения. Если консоль запросов запущена под полными правами, результат ожидаемо будет отличаться.
Выясним еще одну деталь: как запрос взаимодействует с объектом МенеджерВременныхТаблиц. Если у объекта Запрос уже инициализирован менеджер, то использование метода ВыполнитьПакетСПромежуточнымиДанными может вести себя специфично. Платформа создает копии данных для промежуточных итогов.
Посмотрим, как можно проверить наличие данных во временных таблицах без использования отладочного метода, напрямую через менеджер в табло отладчика:
Запрос.МенеджерВременныхТаблиц.Таблицы[0].ПолучитьДанные().Выгрузить()
Важно помнить, что индекс таблицы соответствует порядку её создания в пакете. Если в табло менеджер отображается как Неопределено, значит, он не был назначен объекту запроса явно, и временные таблицы существуют только внутри области видимости метода Выполнить.
Проанализируем конструкцию ЕСТЬNULL(ХозрасчетныйСубконто.Значение, НЕОПРЕДЕЛЕНО). В контексте запросов 1С НЕОПРЕДЕЛЕНО является литералом определенного типа. Если левое соединение не находит соответствия в правой таблице, поле ХозрасчетныйСубконто.Значение становится NULL. Замена NULL на НЕОПРЕДЕЛЕНО может привести к тому, что в дальнейшем фильтры по этой колонке в последующих частях пакета не сработают так, как ожидается, если там сравнивается с пустой ссылкой или другим типом.
При использовании ВыполнитьПакетСПромежуточнымиДанными платформа принудительно типизирует колонки временных таблиц на основе первого полученного значения. Если первая строка результата содержит NULL, который заменяется на НЕОПРЕДЕЛЕНО, тип колонки может определиться некорректно для последующих данных.
Для минимизации "чудес" при отладке пакетных запросов придерживайтесь следующих правил:
ТипЗнч() в табло отладчика непосредственно перед вызовом Выполнить().ВЫРАЗИТЬ для всех полей, выбираемых из параметров в ПОМЕСТИТЬ.ВыполнитьПакетСПромежуточнымиДанными на больших объемах данных (базы терабайтного размера), помните, что метод выгружает все промежуточные итоги в память сервера, что может вызвать временное замедление работы сеанса.Таким образом, расхождение результатов чаще всего вызвано разницей в параметрах сеанса, правах доступа или типах данных, а не ошибкой самого метода платформы. Метод ВыполнитьПакетСПромежуточнымиДанными — это лишь зеркало того, как запрос выполняется в текущий момент времени в конкретном программном контексте.