Часто при разработке отчетов или настройке механизмов доступа к данным мы сталкиваемся с необходимостью фильтровать выборку документов по условиям, связанным с их табличными частями. Нередко программисты выбирают путь наименьшего сопротивления, используя конструкцию ВЫБОР КОГДА прямо в секции ГДЕ. Однако, как показывает практика, это приводит к непредсказуемым результатам, дублированию строк или игнорированию части условий фильтрации. Давайте разберем, почему это происходит и как правильно строить такие запросы.
Основная причина заключается в том, как платформа 1С транслирует запросы 1С в SQL-запросы к базе данных. Когда мы обращаемся к табличной части (ТЧ) внутри секции ГДЕ, 1С пытается выполнить неявное соединение. Если при этом внутри ВЫБОР смешиваются обычные реквизиты документа и данные из вложенной таблицы, оптимизатор СУБД может построить план выполнения, который приводит к декартовому произведению или некорректному объединению множеств.
Рассмотрим пример, который вызывает вопросы:
ВЫБРАТЬ
Док.Ссылка КАК Ссылка
ИЗ
Документ.Док КАК Док
ГДЕ
ВЫБОР
КОГДА &ТекущийПользователь = Док.ААА ТОГДА ИСТИНА
КОГДА &ТекущийПользователь В (Док.ТЧ_ААА.ААА) ТОГДА ИСТИНА
ИНАЧЕ ЛОЖЬ
КОНЕЦ
При таком подходе платформа может «неправильно раскрутить» условие, что приведет к возврату лишних записей. В ряде случаев, особенно при работе с большими объемами данных, этот код может работать нестабильно в зависимости от используемой СУБД (MS SQL, PostgreSQL или файловая версия).
Самый простой и понятный способ избежать «магии» платформы — отказаться от ВЫБОР в пользу стандартных логических операторов. Вместо сложной конструкции мы можем явно описать условия поиска.
Разберем, как сделать это правильно:
ВЫБРАТЬ
Док.Ссылка КАК Ссылка
ИЗ
Документ.Док КАК Док
ГДЕ
&ТекущийПользователь = Док.ААА
ИЛИ &ТекущийПользователь В (ВЫБРАТЬ ДокТЧ.ААА ИЗ Документ.Док.ТЧ_ААА КАК ДокТЧ ГДЕ ДокТЧ.Ссылка = Док.Ссылка)
Такой подход делает запрос прозрачным для оптимизатора. Использование подзапроса внутри оператора В позволяет четко ограничить область поиска только теми строками ТЧ, которые относятся к конкретному документу.
Если вы хотите контролировать логику выборки максимально полно, используйте явное соединение таблиц в секции ИЗ. Это стандарт индустрии разработки на 1С, который исключает скрытые проблемы с производительностью.
Посмотрим на пример реализации через ЛЕВОЕ СОЕДИНЕНИЕ:
ВЫБРАТЬ
Док.Ссылка КАК Ссылка
ИЗ
Документ.Док КАК Док
ЛЕВОЕ СОЕДИНЕНИЕ Документ.Док.ТЧ_ААА КАК ДокААА
ПО Док.Ссылка = ДокААА.Ссылка
И (ДокААА.ААА = &ТекущийПользователь)
ГДЕ
Док.ААА = &ТекущийПользователь
ИЛИ ДокААА.Ссылка ЕСТЬ НЕ NULL
Преимущества данного метода:
ЕСТЬ НЕ NULL позволяет точно определить, нашлась ли запись в табличной части, соответствующая критерию.Если задача заключается в организации прав доступа (RLS) или фильтрации по сложным связям, которые меняются достаточно часто, самым эффективным решением будет создание отдельного РегистраСведений. В этом регистре можно хранить записи вида «Документ — Пользователь».
Почему это надежно:
ПриЗаписи.Работа с табличными частями требует осторожности. Мы выяснили, что использование ВЫБОР КОГДА в фильтрах запросов — это «моветон», который может привести к ошибкам в логике работы программы. Мы рекомендуем:
ЛЕВОЕ СОЕДИНЕНИЕ, если нужно проверить наличие записи в ТЧ.ИЛИ для простых условий.РегистрыСведений.Проанализировав эти методы, вы сможете писать более надежный, производительный и, главное, предсказуемый код на 1С, который будет одинаково успешно работать на любой версии платформы и СУБД.