Почему один и тот же запрос дает разный результат в консоли запросов и СКД и как это исправить

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

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

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

---

Причина 1. Ошибки оптимизатора СКД при использовании условий с ВЫБОР КОГДА

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


ГДЕ
    тблНоменклатура.ЭтоГруппа = ЛОЖЬ
    И ВЫБОР
        КОГДА &ИспользуетсяОтборПоСегментуНоменклатуры = ИСТИНА
            ТОГДА тблНоменклатура.Ссылка В
                (ВЫБРАТЬ
                    ТаблицаОтбора.Номенклатура КАК Номенклатура
                ИЗ
                    ОтборПоСегментуНоменклатуры КАК ТаблицаОтбора)
        ИНАЧЕ ИСТИНА
    КОНЕЦ

В обычной консоли запросов эта конструкция отрабатывает корректно, потому что СУБД получает и выполняет SQL-запрос практически в неизменном виде. Однако в СКД действует собственный мощный оптимизатор запросов. Перед отправкой SQL-кода на сервер СУБД, СКД перестраивает запрос в зависимости от выбранных пользователем полей, группировок и отборов.

Когда оптимизатор СКД сталкивается со сложными условными конструкциями ВЫБОР КОГДА внутри секции ГДЕ, он часто не может однозначно интерпретировать логику условий. В результате СКД может «вырезать» часть условий или неверно связать параметры, посчитав их избыточными. Это приводит к тому, что отбор по виртуальной таблице сегментов просто перестает работать.

Правильное решение:

Для реализации динамических отборов в СКД никогда не следует использовать конструкцию ВЫБОР КОГДА в секции ГДЕ. Вместо этого необходимо задействовать расширение языка запросов СКД — фигурные скобки. Перепишем условие с использованием механизмов компоновки:


ГДЕ
    тблНоменклатура.ЭтоГруппа = ЛОЖЬ
    {ГДЕ (тблНоменклатура.Ссылка В 
        (ВЫБРАТЬ 
            ТаблицаОтбора.Номенклатура 
         ИЗ 
            ОтборПоСегментуНоменклатуры КАК ТаблицаОтбора))}

При таком подходе СКД сама динамически добавит условие соединения с временной таблицей ОтборПоСегментуНоменклатуры только тогда, когда пользователь установит соответствующий флаг или отбор в настройках отчета.

Также стоит учитывать специфику типовых конфигураций на базе ЕРП/КА. В них отборы по сегментам номенклатуры часто управляются программно в модуле объекта отчета через процедуру ПриКомпоновкеРезультата с помощью функций БСП (например, СегментыСервер.ВключитьОтборПоСегментуНоменклатурыВСКД). Если вы используете типовой механизм, убедитесь, что параметры компоновщика настроек инициализируются корректно и не конфликтуют с вашим ручным кодом.

---

Причина 2. Дублирование строк штрихкодов из-за механизма автозаполнения и неявных соединений

Вторая проблема, описанная автором темы, касается дублирования строк номенклатуры из-за вложенного запроса по штрихкодам. Разработчик попытался получить только один уникальный штрихкод для каждой номенклатуры, используя группировку и функцию МАКСИМУМ:


ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
    МАКСИМУМ(ШтрихкодыНоменклатуры.Штрихкод) КАК Штрихкод,
    ШтрихкодыНоменклатуры.Номенклатура КАК Номенклатура,
    ШтрихкодыНоменклатуры.Упаковка КАК Упаковка
ИЗ
    РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыНоменклатуры

СГРУППИРОВАТЬ ПО
    ШтрихкодыНоменклатуры.Номенклатура,
    ШтрихкодыНоменклатуры.Упаковка) КАК тблШтрихкодыУпаковки
ПО тблНоменклатура.Ссылка = тблШтрихкодыУпаковки.Номенклатура
    И тблНоменклатура.КоэффициентЕдиницыДляОтчетов = тблШтрихкодыУпаковки.Упаковка.Числитель

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

  1. Влияние флага «Автозаполнение» в СКД. По умолчанию для наборов данных типа «Запрос» включена опция «Автозаполнение». СКД анализирует итоговые поля компоновки. Если поле Штрихкод выводится в отчет в детальные записи, но для него не определены правила агрегации на вкладке «Ресурсы», оптимизатор СКД может проигнорировать группировку GROUP BY во вложенном запросе и принудительно «раскрыть» её до физической таблицы регистра, чтобы вернуть все штрихкоды номенклатуры.
  2. Разыменование ссылок (обращение через точку) в условиях связи. Это критическая ошибка проектирования запросов в 1С. В условии связи написано: тблНоменклатура.КоэффициентЕдиницыДляОтчетов = тблШтрихкодыУпаковки.Упаковка.Числитель. Поле Упаковка — это ссылка на справочник. Для получения значения реквизита Числитель через точку, СКД под капотом генерирует дополнительное скрытое левое соединение с таблицей упаковок на самом верхнем уровне результирующего SQL-запроса. Это неявное соединение выполняется в обход вашей группировки по максимуму и полностью разрушает логику уникальности строк, вызывая появление дублей.

Правильное решение:

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


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

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

---

Причина 3. Призрачные ошибки («Загадочный кэш») параметров СКД

Довольно часто разработчик сталкивается со следующей ситуацией: он удаляет из запроса обращение к таблице остатков регистра ЗаказыПоставщикам и удаляет неиспользуемый параметр ДатаОтчета. Однако при запуске отчета система продолжает выдавать ошибку:

не задано значение параметра "ДатаОтчета" РегистрНакопления.ЗаказыПоставщикам.Остатки(КОНЕЦПЕРИОДА(&ДатаОтчета, ДЕНЬ)....

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

Когда вы запускаете отчет в режиме «1С:Предприятие», система автоматически загружает последние использованные вами настройки (или настройки по умолчанию) из специального системного хранилища в базе данных (обычно это регистр сведений вариантов отчетов БСП). В этих сохраненных настройках (представляющих собой XML-структуру компоновщика) все еще содержатся упоминания старого параметра ДатаОтчета, старых отборов или выбранных полей, которых физически больше нет в схеме компоновки.

При запуске СКД пытается наложить эти старые сохраненные настройки пользователя на вашу новую измененную схему. Видя несоответствие, платформа выдает ошибку о незаполненном параметре.

Именно поэтому создание нового отчета с чистого листа (как сделал автор темы в Сообщении 12) решает проблему: для нового объекта сгенерировался новый уникальный идентификатор (GUID), в базе данных для него еще не было сохраненных настроек, и СКД успешно запустилась по дефолтной новой схеме.

Как решить проблему с кэшем настроек без создания нового отчета:

  1. В режиме «1С:Предприятие» откройте форму отчета. Нажмите кнопку Еще (в правом верхнем углу) и выберите пункт Установить стандартные настройки. Это принудительно сбросит текущие настройки пользователя и загрузит конфигурационные настройки по умолчанию из вашей новой схемы СКД.
  2. Если вы ведете разработку в тестовой базе, можно запустить сеанс с параметром запуска /C СброситьКэш (этот параметр поддерживается многими механизмами БСП для очистки сохраненных вариантов отчетов).
  3. На этапе конфигуратора можно временно изменить имя отчета или создать новый вариант отчета на вкладке «Настройки» схемы компоновки данных.

Проанализировав эти тонкости работы СКД, мы видим, что система компоновки данных — это не просто транслятор запросов, а интеллектуальный генератор отчетов. Понимание принципов оптимизации запросов СКД, корректное использование фигурных скобок для отборов и знание механизмов кэширования настроек БСП уберегут вас от подобных ошибок и помогут создавать быстрые и стабильные отчеты.

← На главную