Как в 1С выбрать всю номенклатуру с заданными значениями свойств из регистра сведений?

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

При разработке отчетов и обработок в типовых конфигурациях (например, «Управление производственным предприятием 1.3» или «Управление торговлей 10.3») часто возникает задача: взять определенный список позиций номенклатуры, определить для них значения конкретного дополнительного реквизита и затем найти в базе всю остальную номенклатуру, которая обладает точно такими же значениями этого свойства. Однако при попытке связать запросы через подзапрос в секции ГДЕ разработчики часто сталкиваются с тем, что запрос возвращает пустой результат или работает крайне медленно. Разберем типичные ошибки в таких конструкциях и рассмотрим правильные варианты реализации.

Анализ исходной проблемы и ошибок в запросе

Рассмотрим исходный вариант запроса, вызвавший затруднения:


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

СГРУППИРОВАТЬ ПО
    ЗначенияСвойствОбъектов.Значение
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ЗначенияСвойствОбъектов.Объект,
    ЗначенияСвойствОбъектов.Значение
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
ГДЕ
    ЗначенияСвойствОбъектов.Значение В
        (ВЫБРАТЬ
            СписокДопРеквизитов.ЗначениеДопРеквизита
        ИЗ
            СписокДопРеквизитов КАК СписокДопРеквизитов)

Проанализируем, почему этот код работает некорректно или не возвращает данные:

  1. Некорректная передача параметров: если в параметр &МассивНоменклатуры передан пустой массив (количество элементов равно 0), условие В (&МассивНоменклатуры) в платформе гарантированно делает выборку пустой без генерации исключения. Кроме того, измерение Объект имеет составной тип. Если вместо ссылок на элементы справочника Номенклатура случайно переданы строки с кодами, артикулами или пустые ссылки другого типа, совпадений найдено не будет.
  2. Критическая логическая ошибка сопоставления: во втором запросе полностью отсутствует отбор по свойству (Свойство = &Свойство). Ресурс Значение регистра сведений ЗначенияСвойствОбъектов имеет составной тип данных (числа, строки, булево, ссылки на справочник ЗначенияСвойствОбъектов). Если искать объекты только по полю Значение, запрос вернет ложные записи других объектов, у которых совпало значение совершенно другого свойства (например, логическая Истина, число 0 или одинаковая строка).
  3. Неоптимальное условие В (ВЫБРАТЬ ...): использование подзапроса в блоке ГДЕ при работе с временными таблицами значительно уступает по производительности соединению таблиц и часто затрудняет оптимизатору СУБД построение эффективного плана выполнения.
  4. Лишняя группировка: при помещении во временную таблицу группировка не дает выигрыша по скорости, если таблица не индексируется, а при небольшом числе строк создает дополнительную нагрузку на СУБД.

Решение 1: Использование временной таблицы и внутреннего соединения

Оптимизируем логику: во втором запросе заменим условие В (ВЫБРАТЬ ...) на ВНУТРЕННЕЕ СОЕДИНЕНИЕ, добавим явный отбор по целевому свойству и проиндексируем поле связи во временной таблице. Также воспользуемся оператором ВЫРАЗИТЬ для однозначного приведения типа поля Объект.


ВЫБРАТЬ РАЗЛИЧНЫЕ
    ЗначенияСвойствОбъектов.Значение КАК Значение
ПОМЕСТИТЬ ВТ_ЗначенияСвойств
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
ГДЕ
    ЗначенияСвойствОбъектов.Объект В(&МассивНоменклатуры)
    И ЗначенияСвойствОбъектов.Свойство = &Свойство
ИНДЕКСИРОВАТЬ ПО
    Значение
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Объект КАК Справочник.Номенклатура) КАК Номенклатура,
    ЗначенияСвойствОбъектов.Значение КАК Значение
ИЗ
    РегистрСведений.ЗначенияСвойствОбъектов КАК ЗначенияСвойствОбъектов
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ ВТ_ЗначенияСвойств КАК ВТ_ЗначенияСвойств
        ПО ЗначенияСвойствОбъектов.Значение = ВТ_ЗначенияСвойств.Значение
ГДЕ
    ЗначенияСвойствОбъектов.Свойство = &Свойство
    И ЗначенияСвойствОбъектов.Объект ССЫЛКА Справочник.Номенклатура

Разберем ключевые моменты этой реализации:

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

Решение 2: Соединение регистра с самим собой в одном запросе

Если нет необходимости выполнять сложную постобработку данных или сохранять промежуточные результаты, можно обойтись без создания временных таблиц с помощью самосоединения (Self-Join) регистра сведений:


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

Посмотрим на особенности этого подхода:

  1. Запрос выполняется в один шаг без накладных расходов на создание и наполнение таблиц в базе tempdb.
  2. Связь сразу строится и по полю Свойство, и по полю Значение, что гарантирует точное совпадение значений именно в рамках искомой характеристики.

Дополнительные рекомендации по производительности и типам данных

При работе с регистром ЗначенияСвойствОбъектов важно учитывать физическое устройство метаданных:

  1. Проверка заполненности параметров: перед выполнением запроса в коде 1С обязательно проверяйте, что МассивНоменклатуры.Количество() > 0, и что параметр &Свойство является ссылкой на план видов характеристик СвойстваОбъектов.
  2. Строки неограниченной длины: если в качестве значения дополнительного реквизита может выступать строка неограниченной длины, платформа не позволит выполнить индексацию или соединение без явного приведения. В таких случаях используйте ВЫРАЗИТЬ(ЗначенияСвойствОбъектов.Значение КАК Строка(100)).
  3. Пометка на удаление: чтобы исключить из итогового результата помеченные на удаление позиции номенклатуры, дополните условие проверкой: И НЕ ВЫРАЗИТЬ(ВсеОбъекты.Объект КАК Справочник.Номенклатура).ПометкаУдаления.
← На главную