При разработке отчетов и обработок в 1С часто возникает задача выбрать данные из документов или регистров, отфильтровав их по принадлежности к определенным группам справочника. Иногда программисты пытаются использовать привычные методы объектной модели, такие как НайтиПоКоду или НайтиПоНаименованию, прямо внутри текста запроса. Давайте разберем, почему это приводит к ошибкам и как сделать правильно.
Язык запросов 1С — это декларативный инструмент, который транслирует ваш код в SQL-запрос к серверу баз данных. Сервер БД не знает ничего о «1С-ных» объектах, методах Справочники.Номенклатура.НайтиПоКоду() или контексте исполнения вашего кода. Он оперирует исключительно таблицами и связями между ними.
Когда вы пишете ГДЕ Номенклатура В ИЕРАРХИИ(Значение(Справочники.Номенклатура.НайтиПоКоду(...))), система пытается выполнить недопустимую операцию. Запрос не является местом для вызова функций объектной модели. Все необходимые данные (ссылки, значения) должны быть подготовлены заранее в процедурном коде и переданы в запрос через параметры.
Самый надежный и быстрый способ — это передача готовых ссылок на группы справочника. Вы заранее находите нужные папки в процедурном коде, а затем передаете их в запрос. Рассмотрим пример реализации:
// В модуле объекта или менеджера
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Продукция.Номенклатура,
| Продукция.Количество
|ИЗ
| Документ.ОтчетПроизводстваЗаСмену.Продукция КАК Продукция
|ГДЕ
| Продукция.Номенклатура В ИЕРАРХИИ(&СписокГрупп)";
СписокГрупп = Новый Массив;
СписокГрупп.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000001116"));
СписокГрупп.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000001117"));
Запрос.УстановитьПараметр("СписокГрупп", СписокГрупп);
Результат = Запрос.Выполнить();
Используя конструкцию В ИЕРАРХИИ(&СписокГрупп), мы заставляем систему оптимизированно выбирать все элементы, входящие в указанные папки, что работает значительно быстрее, чем любая фильтрация по наименованиям или кодам в самом запросе.
Если группы номенклатуры часто меняются и вы не хотите хардкодить их в коде, стоит рассмотреть более гибкие архитектурные подходы:
Сегменты. Вы просто включаете товар в сегмент, а в запросе делаете отбор по этому сегменту. Это исключает необходимость менять код при изменении состава групп.РегистрСведений с измерением Номенклатура и ресурсом ПризнакБрака. Это правильное решение, обеспечивающее высокую производительность системы.Иногда возникает соблазн использовать конструкции типа Номенклатура.Родитель.Наименование = "Брак". Мы настоятельно рекомендуем избегать этого.
Номенклатура.Родитель.Наименование, система выполняет множество левых соединений (LEFT JOIN) с таблицами справочника для каждой строки выборки.Если вам нужно сравнить родителя, используйте сравнение ссылок: Номенклатура.Родитель = &ГруппаБрака, где &ГруппаБрака — это заранее найденная ссылка на папку.
Подводя черту, запомните золотое правило 1С-разработки: запрос должен быть чистым. Всю предварительную логику (поиск ссылок, формирование списков значений, вычисление периодов) выполняйте во встроенном языке, а в запрос передавайте уже готовые данные через параметры. Это сделает ваш код профессиональным, производительным и удобным для поддержки.