Каждый разработчик на платформе 1С:Предприятие рано или поздно сталкивается с загадочной ситуацией: сложный и выверенный запрос идеально работает в консоли запросов, но при переносе в схему компоновки данных (СКД) начинает вести себя непредсказуемо. Он может выводить пустой результат, дублировать строки номенклатуры или выдавать ошибки о несуществующих параметрах, которых в тексте запроса уже давно нет.
В этой статье мы подробно проанализируем внутренние механизмы платформы 1С, выясним причины такого расхождения в поведении и разберем по шагам, как исправить самые распространенные проблемы СКД: некорректную фильтрацию по сегментам, дублирование записей из-за автозаполнения и появление фантомных ошибок кэширования настроек.
---
Рассмотрим структуру первого запроса, с которым возникли проблемы у автора темы. В финальном пакете запроса используется следующее условие в секции ГДЕ:
ГДЕ
тблНоменклатура.ЭтоГруппа = ЛОЖЬ
И ВЫБОР
КОГДА &ИспользуетсяОтборПоСегментуНоменклатуры = ИСТИНА
ТОГДА тблНоменклатура.Ссылка В
(ВЫБРАТЬ
ТаблицаОтбора.Номенклатура КАК Номенклатура
ИЗ
ОтборПоСегментуНоменклатуры КАК ТаблицаОтбора)
ИНАЧЕ ИСТИНА
КОНЕЦ
В обычной консоли запросов эта конструкция отрабатывает корректно, потому что СУБД получает и выполняет SQL-запрос практически в неизменном виде. Однако в СКД действует собственный мощный оптимизатор запросов. Перед отправкой SQL-кода на сервер СУБД, СКД перестраивает запрос в зависимости от выбранных пользователем полей, группировок и отборов.
Когда оптимизатор СКД сталкивается со сложными условными конструкциями ВЫБОР КОГДА внутри секции ГДЕ, он часто не может однозначно интерпретировать логику условий. В результате СКД может «вырезать» часть условий или неверно связать параметры, посчитав их избыточными. Это приводит к тому, что отбор по виртуальной таблице сегментов просто перестает работать.
Правильное решение:
Для реализации динамических отборов в СКД никогда не следует использовать конструкцию ВЫБОР КОГДА в секции ГДЕ. Вместо этого необходимо задействовать расширение языка запросов СКД — фигурные скобки. Перепишем условие с использованием механизмов компоновки:
ГДЕ
тблНоменклатура.ЭтоГруппа = ЛОЖЬ
{ГДЕ (тблНоменклатура.Ссылка В
(ВЫБРАТЬ
ТаблицаОтбора.Номенклатура
ИЗ
ОтборПоСегментуНоменклатуры КАК ТаблицаОтбора))}
При таком подходе СКД сама динамически добавит условие соединения с временной таблицей ОтборПоСегментуНоменклатуры только тогда, когда пользователь установит соответствующий флаг или отбор в настройках отчета.
Также стоит учитывать специфику типовых конфигураций на базе ЕРП/КА. В них отборы по сегментам номенклатуры часто управляются программно в модуле объекта отчета через процедуру ПриКомпоновкеРезультата с помощью функций БСП (например, СегментыСервер.ВключитьОтборПоСегментуНоменклатурыВСКД). Если вы используете типовой механизм, убедитесь, что параметры компоновщика настроек инициализируются корректно и не конфликтуют с вашим ручным кодом.
---
Вторая проблема, описанная автором темы, касается дублирования строк номенклатуры из-за вложенного запроса по штрихкодам. Разработчик попытался получить только один уникальный штрихкод для каждой номенклатуры, используя группировку и функцию МАКСИМУМ:
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
МАКСИМУМ(ШтрихкодыНоменклатуры.Штрихкод) КАК Штрихкод,
ШтрихкодыНоменклатуры.Номенклатура КАК Номенклатура,
ШтрихкодыНоменклатуры.Упаковка КАК Упаковка
ИЗ
РегистрСведений.ШтрихкодыНоменклатуры КАК ШтрихкодыНоменклатуры
СГРУППИРОВАТЬ ПО
ШтрихкодыНоменклатуры.Номенклатура,
ШтрихкодыНоменклатуры.Упаковка) КАК тблШтрихкодыУпаковки
ПО тблНоменклатура.Ссылка = тблШтрихкодыУпаковки.Номенклатура
И тблНоменклатура.КоэффициентЕдиницыДляОтчетов = тблШтрихкодыУпаковки.Упаковка.Числитель
Проанализируем, почему этот подзапрос отлично работает в консоли, но дублирует записи в СКД. Здесь кроются сразу две серьезные архитектурные ошибки:
Штрихкод выводится в отчет в детальные записи, но для него не определены правила агрегации на вкладке «Ресурсы», оптимизатор СКД может проигнорировать группировку GROUP BY во вложенном запросе и принудительно «раскрыть» её до физической таблицы регистра, чтобы вернуть все штрихкоды номенклатуры.тблНоменклатура.КоэффициентЕдиницыДляОтчетов = тблШтрихкодыУпаковки.Упаковка.Числитель. Поле Упаковка — это ссылка на справочник. Для получения значения реквизита Числитель через точку, СКД под капотом генерирует дополнительное скрытое левое соединение с таблицей упаковок на самом верхнем уровне результирующего SQL-запроса. Это неявное соединение выполняется в обход вашей группировки по максимуму и полностью разрушает логику уникальности строк, вызывая появление дублей.Правильное решение:
Чтобы избежать дублирования строк, необходимо вынести получение всех реквизитов ссылочного типа непосредственно внутрь вложенного запроса и соединять таблицы исключительно по полям простых типов (числа, строки). Перепишем соединение штрихкодов правильно:
// Вложенный запрос по штрихкодам с предварительным получением числителя упаковки
ЛЕВОЕ СОЕДИНЕНИЕ (ВЫБРАТЬ
МАКСИМУМ(Штрихкоды.Штрихкод) КАК Штрихкод,
Штрихкоды.Номенклатура КАК Номенклатура,
Штрихкоды.Упаковка.Числитель КАК ЧислительУпаковки
ИЗ
РегистрСведений.ШтрихкодыНоменклатуры КАК Штрихкоды
СГРУППИРОВАТЬ ПО
Штрихкоды.Номенклатура,
Штрихкоды.Упаковка.Числитель) КАК тблШтрихкодыУпаковки
ПО тблНоменклатура.Ссылка = тблШтрихкодыУпаковки.Номенклатура
И тблНоменклатура.КоэффициентЕдиницыДляОтчетов = тблШтрихкодыУпаковки.ЧислительУпаковки
В таком варианте СКД не будет выполнять неявных разыменований на верхнем уровне, группировка отработает корректно, и дубли штрихкодов гарантированно исчезнут.
---
Довольно часто разработчик сталкивается со следующей ситуацией: он удаляет из запроса обращение к таблице остатков регистра ЗаказыПоставщикам и удаляет неиспользуемый параметр ДатаОтчета. Однако при запуске отчета система продолжает выдавать ошибку:
не задано значение параметра "ДатаОтчета" РегистрНакопления.ЗаказыПоставщикам.Остатки(КОНЕЦПЕРИОДА(&ДатаОтчета, ДЕНЬ)....
Многие списывают это на серверный кэш платформы, чистят временные файлы или просят системного администратора перезапустить службу сервера 1С. На самом деле причина кроется в механизме работы Хранилища настроек (БСП).
Когда вы запускаете отчет в режиме «1С:Предприятие», система автоматически загружает последние использованные вами настройки (или настройки по умолчанию) из специального системного хранилища в базе данных (обычно это регистр сведений вариантов отчетов БСП). В этих сохраненных настройках (представляющих собой XML-структуру компоновщика) все еще содержатся упоминания старого параметра ДатаОтчета, старых отборов или выбранных полей, которых физически больше нет в схеме компоновки.
При запуске СКД пытается наложить эти старые сохраненные настройки пользователя на вашу новую измененную схему. Видя несоответствие, платформа выдает ошибку о незаполненном параметре.
Именно поэтому создание нового отчета с чистого листа (как сделал автор темы в Сообщении 12) решает проблему: для нового объекта сгенерировался новый уникальный идентификатор (GUID), в базе данных для него еще не было сохраненных настроек, и СКД успешно запустилась по дефолтной новой схеме.
Как решить проблему с кэшем настроек без создания нового отчета:
/C СброситьКэш (этот параметр поддерживается многими механизмами БСП для очистки сохраненных вариантов отчетов).Проанализировав эти тонкости работы СКД, мы видим, что система компоновки данных — это не просто транслятор запросов, а интеллектуальный генератор отчетов. Понимание принципов оптимизации запросов СКД, корректное использование фигурных скобок для отборов и знание механизмов кэширования настроек БСП уберегут вас от подобных ошибок и помогут создавать быстрые и стабильные отчеты.