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

Программист 1С v8.3 (Управляемые формы)
← На главную

В практике разработки на платформе 1С часто возникает ситуация, когда необходимо выбрать данные из справочника или документа, но при этом полностью исключить объект из итоговой выборки, если в его табличной части (или связанном регистре сведений) встречается хотя бы одна строка с определённым значением. Начинающие разработчики часто допускают ошибку, пытаясь решить задачу "в лоб" через простое условие в секции ГДЕ, что приводит к некорректным результатам. В этой статье мы подробно разберем, почему стандартные фильтры не работают в таких случаях, и изучим три эффективных способа решения задачи.

Анализ проблемы: почему обычное условие ГДЕ не работает

Рассмотрим ситуацию, описанную в теме: у нас есть объект (например, из регистра _ридОбъектыТехники), к которому привязано несколько правообладателей в другом регистре (_ридПравообладатели). Если мы напишем условие:

ГДЕ _ридПравообладатели.Правообладатель <> &ЗапрещенныйПравообладатель

Мы получим ошибку логики. Запрос исключит только ту конкретную строку, где правообладатель совпал с параметром. Однако у объекта могут быть другие строки с другими правообладателями. В итоге объект всё равно попадет в выборку, просто в "усеченном" виде, без одной строки. Наша же задача — полностью исключить объект, если в его списке есть хотя бы одно "запрещенное" совпадение.

Проанализируем пошагово правильные методы решения этой задачи.

Способ 1. Использование вложенного запроса с оператором НЕ В

Это самый понятный и логичный способ с точки зрения человеческого языка. Мы сначала составляем "черный список" идентификаторов объектов, которые нам не подходят, а затем исключаем их из основной выборки.

Разберем реализацию этого метода:


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

Преимущества: Высокая читаемость кода. Легко понять, что мы выбираем все записи, кроме тех, чьи идентификаторы попали во вложенный запрос.

Нюансы: При работе с огромными массивами данных (миллионы записей) оператор НЕ В может работать медленнее, чем соединения, так как СУБД не всегда эффективно оптимизирует такие вложенные конструкции.

Способ 2. Левое соединение с проверкой на NULL

Этот метод считается "золотым стандартом" производительности в 1С. Мы пытаемся соединить основную таблицу с таблицей "нарушителей". Если соединение не удалось (результат равен NULL), значит, объект чист и его можно брать в выборку.

Рассмотрим алгоритм действий:

  1. Выбираем основные данные.
  2. Присоединяем таблицу правообладателей по ссылке (РИД).
  3. В условии соединения (секция ПО) указываем не только равенство ссылок, но и фильтр по нашему "запрещенному" параметру.
  4. В секции ГДЕ оставляем только те строки, где правая таблица оказалась пустой.

Пример кода:


ВЫБРАТЬ
    Объекты.РИД.НомерОД КАК РИДНомерОД,
    Объекты.РИД КАК РИД
ИЗ
    РегистрСведений._ридОбъектыТехники КАК Объекты
        ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений._ридПравообладатели КАК ФильтрПравообладатели
        ПО Объекты.РИД = ФильтрПравообладатели.РИД
            И ФильтрПравообладатели.Правообладатель = &ПараметрПравообладатель
ГДЕ
    ФильтрПравообладатели.РИД ЕСТЬ NULL
    И Объекты.ТипРИД = &ТипРИД

Важный момент: Обратите внимание, что условие ФильтрПравообладатели.Правообладатель = &ПараметрПравообладатель вынесено в секцию ПО, а не в ГДЕ. Это критически важно для работы ЛЕВОГО СОЕДИНЕНИЯ. Если мы вынесем это в ГДЕ, мы превратим левое соединение во внутреннее и потеряем смысл всей операции.

Способ 3. Использование временных таблиц (Метод исключения)

Для сложных запросов, где участвует много таблиц и условий, лучше всего использовать временные таблицы (ВТ). Это сделает запрос структурированным и позволит СУБД лучше построить план выполнения.

Разберем решение по этапам:

Этап 1. Подготовка списка "запрещенных" объектов. Мы создаем ВТ, в которой будут лежать только ссылки на объекты, имеющие ненужного правообладателя.


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

Этап 2. Итоговая выборка. Выбираем данные, соединяясь с этой ВТ и отсекая совпадения.


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

Этот метод исключает появление дублей и позволяет очень гибко настраивать условия фильтрации. Мы четко разделяем логику: "кто нам не нравится" и "какие данные мы хотим получить из тех, кто остался".

Сводная таблица методов

Проанализируем, какой метод выбрать в зависимости от условий задачи:

  1. Вложенный запрос (НЕ В): Подходит для небольших баз и простых отчетов, где важна читаемость.
  2. Левое соединение (NULL): Оптимально для высоконагруженных систем и типовых механизмов.
  3. Временные таблицы: Лучший выбор для сложных комплексных запросов, где один и тот же фильтр нужно применить к нескольким источникам данных.

Типичные ошибки при реализации

Выясним причины, по которым запрос может продолжать возвращать "лишние" строки даже после применения фильтров:

1. Забытое условие РАЗЛИЧНЫЕ. Если вы используете соединения и у объекта много строк в ТЧ, в результате запроса объект может продублироваться столько раз, сколько у него строк. Всегда проверяйте необходимость использования ВЫБРАТЬ РАЗЛИЧНЫЕ.

2. Фильтрация по значению вместо ссылки. При работе с NULL важно проверять именно ключевое поле соединения (например, Ссылка или РИД), а не вспомогательные реквизиты, которые сами по себе могут быть не заполнены в базе.

3. Конфликт условий. Проверьте, что в секции ГДЕ другие условия (например, по ТипРИД) не отсекают записи раньше, чем сработает логика исключения правообладателей. Помните о приоритетах выполнения операций в SQL.

Используя предложенные методы, вы сможете гарантированно исключать из выборки любые объекты, которые не соответствуют вашим критериям, даже если эти критерии скрыты глубоко в подчиненных табличных частях.

← На главную