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