Разработчики 1С часто сталкиваются с ситуацией, когда один и тот же запрос, выполненный в Консоли запросов, выдает корректные данные, а в отчете на базе Системы компоновки данных (СКД) — нет. Это создает ложное впечатление, что в коде запроса допущена ошибка, хотя на самом деле причина часто кроется в механизмах работы самой платформы 1С. Рассмотрим подробно, почему так происходит и как с этим бороться.
Для начала разберем фундаментальное различие. Консоль запросов исполняет текст запроса практически «как есть», напрямую обращаясь к СУБД. СКД же является мощным генератором: перед выполнением она анализирует схему, настройки пользователя, выбранные поля и отборы, а затем перестраивает исходный запрос для оптимизации. Проанализируем основные факторы, влияющие на этот процесс.
ЛЕВОМ СОЕДИНЕНИИ, СКД может просто выкинуть эту таблицу из итогового запроса. Если на эту таблицу было наложено условие в секции ГДЕ, логика отчета нарушится.Рассмотрим ситуацию, описанную в теме. В запросе используются временные таблицы для сбора данных по заказам, производству и выпуску продукции. Посмотрим на фрагмент итогового объединения:
ВЫБРАТЬ
Перемещение.Номенклатура КАК Номенклатура,
Перемещение.Характеристика КАК Характеристика,
СУММА(Перемещение.КоличествоУпаковок - ЕСТЬNULL(Производство.КоличествоУпаковок, 0)) КАК ОсталосьЗаказать,
ЕСТЬNULL(Выпуск.КоличествоУпаковок, 0) КАК Выпущено,
Перемещение.Ссылка КАК Ссылка,
СостоянияВнутреннихЗаказов.Заказ КАК Заказ
ИЗ
РегистрСведений.СостоянияВнутреннихЗаказов КАК СостоянияВнутреннихЗаказов
ЛЕВОЕ СОЕДИНЕНИЕ Перемещение КАК Перемещение
ПО СостоянияВнутреннихЗаказов.Заказ = Перемещение.Ссылка
ГДЕ
СостоянияВнутреннихЗаказов.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияВнутреннихЗаказов.ГотовКОбеспечению)
В данном случае условие ГДЕ наложено на основную таблицу СостоянияВнутреннихЗаказов. Если компоновщик СКД решит, что поле Состояние не является обязательным для вывода, он может некорректно применить фильтрацию в итоговом SQL-запросе.
Одной из рекомендаций при работе с СКД является перенос условий фильтрации из секции ГДЕ непосредственно в условия соединения ПО. Это гарантирует, что фильтрация будет применена на уровне соединения таблиц, что более предсказуемо для компоновщика макета. Попробуем изменить структуру соединения:
ИЗ
РегистрСведений.СостоянияВнутреннихЗаказов КАК СостоянияВнутреннихЗаказов
ЛЕВОЕ СОЕДИНЕНИЕ Перемещение КАК Перемещение
ПО СостоянияВнутреннихЗаказов.Заказ = Перемещение.Ссылка
И СостоянияВнутреннихЗаказов.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияВнутреннихЗаказов.ГотовКОбеспечению)
Важно: При использовании ЛЕВОГО СОЕДИНЕНИЯ такое изменение может изменить логику выборки (в результат попадут все записи из левой таблицы, даже если условие не выполнено, но с пустыми полями правой таблицы). В данном конкретном случае, так как СостоянияВнутреннихЗаказов является ведущей таблицей, это может помочь стабилизировать результат в СКД.
Если вы хотите, чтобы определенные поля или таблицы всегда участвовали в запросе, независимо от того, выбрал ли их пользователь в настройках отчета, выполним следующие шаги в конструкторе СКД:
Состояние и Заказ установим флаг «Обязательное».Проанализируем ситуацию, когда компоновщик удаляет поля. Если поле участвует в группировке в тексте запроса (СГРУППИРОВАТЬ ПО), но не используется в настройках структуры СКД, компоновщик может упростить запрос, убрав «лишние» с его точки зрения данные. Установка флага «Обязательное» запрещает системе проводить такую оптимизацию.
Как выяснилось в ходе обсуждения, часто проблема решается банальным созданием нового отчета или очисткой сохраненных настроек. Разберем по шагам, что нужно сделать, если запрос верный, но отчет упрямо выдает старые данные:
Имя (не путать с синонимом) в свойствах корневого объекта в конфигураторе. Это заставит систему воспринимать его как новый объект и игнорировать старый кэш.ГДЕ.Чтобы жестко зафиксировать условие в запросе СКД и не дать компоновщику его игнорировать, рекомендуется использовать фигурные скобки. Это позволяет явно указать места для вставки отборов:
ГДЕ
СостоянияВнутреннихЗаказов.Состояние = ЗНАЧЕНИЕ(Перечисление.СостоянияВнутреннихЗаказов.ГотовКОбеспечению)
И СостоянияВнутреннихЗаказов.Заказ {(&ЗаказОтбор)}
Такой подход делает запрос более гибким и понятным для механизмов компоновки. Выясним причину, почему создание нового отчета помогло автору темы: при создании нового объекта 1С генерирует новый уникальный идентификатор (UID). Все старые настройки, кэши и ошибки интерпретации метаданных, привязанные к старому ID, перестают влиять на выполнение кода.
Подведем итог: При расхождениях данных между консолью и отчетом первым делом проверяйте обязательность полей в схеме СКД и чистоту пользовательских настроек. В 90% случаев проблема кроется именно в «интеллектуальной» оптимизации запроса компоновщиком или в кэшировании старых версий схемы.