Почему запрос 1С игнорирует фильтр по менеджеру и как правильно использовать ИЛИ в условиях

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

В практике разработки на платформе 1С:Предприятие часто возникают ситуации, когда запрос, казалось бы, написанный верно, возвращает «лишние» строки. Одной из самых коварных ошибок является неправильное сочетание логических операторов И (AND) и ИЛИ (OR). Рассмотрим ситуацию, когда при наличии условия по конкретному менеджеру в выборку все равно попадают данные других сотрудников.

Разберем исходную проблему

Проанализируем фрагмент запроса, который вызывал затруднения. Разработчик хотел получить контактную информацию контрагентов, закрепленных за определенным менеджером, при условии, что в поле адреса (Поле4) встречаются названия определенных городов.

Посмотрим на исходный код условия в блоке ГДЕ:


ГДЕ
    (Контрагенты.Менеджер = &Менеджер
                И КонтактнаяИнформация.Поле4 <> &Поле4
                И КонтактнаяИнформация.Поле4 ПОДОБНО "%Сатка%"
            ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Усть-Катав%"
            ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Аша%"
            ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Катав-Ивановск%"
            ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Куса%")

На первый взгляд кажется, что все условия находятся внутри общих скобок и должны работать совместно. Однако здесь вступает в силу правило приоритета логических операций. В языке запросов 1С (как и в стандартном SQL) оператор И имеет более высокий приоритет, чем оператор ИЛИ. Это означает, что система сначала вычисляет цепочку условий, соединенных через И, а затем объединяет результат с условиями через ИЛИ.

Фактически, система прочитала условие следующим образом:

  1. Выбрать записи, где (Менеджер равен параметру И Поле4 содержит "Сатка").
  2. ЛИБО выбрать любые записи, где Поле4 содержит "Усть-Катав".
  3. ЛИБО выбрать любые записи, где Поле4 содержит "Аша" (независимо от менеджера).

Именно поэтому в итоговый результат попадали строки с другими менеджерами: они удовлетворяли условиям, стоящим после первого оператора ИЛИ.

Решение проблемы: правильная группировка скобками

Чтобы заставить фильтр по менеджеру работать для всех городов, нам необходимо явно указать порядок выполнения операций. Мы должны «сгруппировать» все условия по городам в один блок, чтобы менеджер применялся к результату этого блока. Рассмотрим исправленный вариант:


ГДЕ
    Контрагенты.Менеджер = &Менеджер
    И (КонтактнаяИнформация.Поле4 ПОДОБНО "%Сатка%"
        ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Усть-Катав%"
        ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Аша%"
        ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Катав-Ивановск%"
        ИЛИ КонтактнаяИнформация.Поле4 ПОДОБНО "%Куса%")

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

Важные нюансы работы с соединениями и NULL

Рассматривая этот запрос, мы должны обратить внимание на еще одну важную деталь. В тексте используется ЛЕВОЕ СОЕДИНЕНИЕ регистра сведений со справочником контрагентов. Однако фильтрация по менеджеру происходит в блоке ГДЕ.

Выясним причину, почему это важно: когда мы накладываем условие на поле из правой таблицы (Контрагенты) в блоке ГДЕ, наше ЛЕВОЕ СОЕДИНЕНИЕ фактически превращается во ВНУТРЕННЕЕ. Если в регистре есть запись, для которой контрагент не найден (или поле Объект пустое), поле Менеджер будет содержать NULL. Сравнение NULL = &Менеджер всегда дает результат Ложь, и такие записи будут отсечены.

Если ваша задача — сохранить в результате все записи контактной информации (даже без контрагентов), но для существующих контрагентов проверить менеджера, условие нужно перенести из блока ГДЕ в условие связи ПО:


ИЗ
    РегистрСведений.КонтактнаяИнформация КАК КонтактнаяИнформация
        ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагенты
        ПО КонтактнаяИнформация.Объект = Контрагенты.Ссылка
        И Контрагенты.Менеджер = &Менеджер

Производительность оператора ПОДОБНО

Проанализируем использование конструкции ПОДОБНО "%Текст%". Использование символа процента в начале строки поиска является крайне ресурсоемкой операцией для базы данных. Важно помнить: такие условия не могут использовать индексы. СУБД будет вынуждена выполнить полное сканирование таблицы (Full Scan), что на больших объемах данных (например, в регистре с миллионами записей контактной информации) приведет к существенным тормозам.

Если вам часто требуется подобный поиск, рекомендуется рассмотреть следующие варианты:

Использование группировки для удаления дублей

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

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

← На главную