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