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