Как правильно фильтровать данные по иерархии в запросах 1С?

Программист 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Управленческий учет Промышленность, строительство и АПК
← На главную

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

Почему использование методов объекта в запросе вызывает ошибку?

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

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

Правильный способ №1: Передача параметров

Самый надежный и быстрый способ — это передача готовых ссылок на группы справочника. Вы заранее находите нужные папки в процедурном коде, а затем передаете их в запрос. Рассмотрим пример реализации:


// В модуле объекта или менеджера
Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Продукция.Номенклатура,
    |	Продукция.Количество
    |ИЗ
    |	Документ.ОтчетПроизводстваЗаСмену.Продукция КАК Продукция
    |ГДЕ
    |	Продукция.Номенклатура В ИЕРАРХИИ(&СписокГрупп)";

СписокГрупп = Новый Массив;
СписокГрупп.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000001116"));
СписокГрупп.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000001117"));

Запрос.УстановитьПараметр("СписокГрупп", СписокГрупп);
Результат = Запрос.Выполнить();

Используя конструкцию В ИЕРАРХИИ(&СписокГрупп), мы заставляем систему оптимизированно выбирать все элементы, входящие в указанные папки, что работает значительно быстрее, чем любая фильтрация по наименованиям или кодам в самом запросе.

Правильный способ №2: Использование сегментов или регистров

Если группы номенклатуры часто меняются и вы не хотите хардкодить их в коде, стоит рассмотреть более гибкие архитектурные подходы:

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

Чего делать не стоит: разворачивание через точки

Иногда возникает соблазн использовать конструкции типа Номенклатура.Родитель.Наименование = "Брак". Мы настоятельно рекомендуем избегать этого.

Если вам нужно сравнить родителя, используйте сравнение ссылок: Номенклатура.Родитель = &ГруппаБрака, где &ГруппаБрака — это заранее найденная ссылка на папку.

Итоги

Подводя черту, запомните золотое правило 1С-разработки: запрос должен быть чистым. Всю предварительную логику (поиск ссылок, формирование списков значений, вычисление периодов) выполняйте во встроенном языке, а в запрос передавайте уже готовые данные через параметры. Это сделает ваш код профессиональным, производительным и удобным для поддержки.

← На главную