К статье
Практический материал

Разработка и Конфигурация · 10 мин

1С: когда использовать НЕ, а когда отрицание через <> и ИЛИ

Разбираем, когда в 1С лучше использовать НЕ, а когда — отрицание через <>, ИЛИ и другие конструкции. Примеры для запросов, кода и отборов с разбором ошибок.

Вопрос «что лучше использовать — НЕ или альтернативное условие» возникает у разработчиков 1С в трёх типовых ситуациях: в языке запросов (НЕ против <>), в условных операторах встроенного языка (НЕ против сравнения с Ложь) и в отборах динамических списков и СКД. Универсального ответа нет: выбор влияет на читаемость кода, а в запросах — ещё и на производительность и корректность при работе со значением NULL.

Главная практическая разница в том, что оператор НЕ инвертирует результат условия целиком, а заменяющее условие (<>, прямое сравнение, отсутствие отбора) формулирует критерий напрямую. В простых случаях оба варианта эквивалентны, но при работе с NULL, с составными типами и внутри сложных логических выражений поведение может разойтись — и запрос молча вернёт не те строки.

Где вообще применяется НЕ в 1С

Оператор НЕ существует в двух языках платформы. Во встроенном языке (модули) это логический оператор, который работает только с булевыми значениями: Если НЕ Отказ Тогда ... КонецЕсли;. В языке запросов НЕ применяется в секции ГДЕ и в условиях соединений: ГДЕ НЕ Товары.ПометкаУдаления.

Важно понимать, что это разные механизмы. В коде НЕ вычисляется интерпретатором и влияет только на читаемость. В запросе условие транслируется в SQL, и там вступают в силу правила трёхзначной логики СУБД: результат сравнения с NULL — не Истина и не Ложь, а «неопределённость», которая отсекается из выборки. Именно поэтому НЕ в запросе требует большего внимания, чем в коде.

НЕ против <> в языке запросов

Типовая ситуация: нужно отобрать документы, где контрагент не равен конкретному значению. Два варианта:

ГДЕ НЕ Док.Контрагент = &Контрагент

ГДЕ Док.Контрагент <> &Контрагент

Для обязательного реквизита, который не может быть NULL, оба условия дадут одинаковый результат. Но второй вариант предпочтительнее: он читается напрямую, без логической инверсии, и планировщику СУБД проще подобрать индекс. Отрицание целого выражения через НЕ может мешать использованию индексов в некоторых СУБД, особенно когда НЕ стоит перед сложным составным условием.

Разница становится критичной, если поле может содержать NULL — например, это реквизит составного типа или результат левого соединения. Условие Поле <> &Значение отсекает строки с NULL: сравнение даёт «неопределённость». Условие НЕ Поле = &Значение ведёт себя так же — NULL тоже не пройдёт. Если нужно включить строки с пустым значением, добавляйте явную проверку:

ГДЕ Док.Контрагент <> &Контрагент

ИЛИ Док.Контрагент ЕСТЬ NULL

НЕ в составных условиях и правила де Моргана

Когда НЕ стоит перед скобкой с несколькими условиями, выражение часто можно и стоит переписать по правилам де Моргана. Условие НЕ (А И Б) эквивалентно НЕ А ИЛИ НЕ Б, а НЕ (А ИЛИ Б) — это НЕ А И НЕ Б. Раскрытая форма обычно читается лучше, потому что каждое подусловие проверяется напрямую.

Например, вместо НЕ (Проведен И ПометкаУдаления) в запросе понятнее написать НЕ Проведен ИЛИ НЕ ПометкаУдаления. Однако не увлекайтесь: если инвертируется сложное условие из пяти-шести частей, одна скобка с НЕ может быть короче и надёжнее, чем развёрнутая цепочка, где легко ошибиться в приоритете операторов.

Отдельная ошибка — забыть скобки. Выражение НЕ А И Б означает (НЕ А) И Б, а не НЕ (А И Б): у НЕ самый высокий приоритет. Если смысл требует инверсии всего выражения, скобки обязательны, даже если вам кажется, что «и так понятно».

Типичные ошибки с НЕ
01
НЕ А И Б вместо НЕ (А И Б) — из-за приоритета инвертируется только первое условие, и отбор работает не так, как задумано
02
Двойное отрицание вида НЕ НЕ Проведен — запутывает код, заменяется на Проведен
03
Сравнение НЕ Флаг = Истина — избыточно и хуже читается, чем просто НЕ Флаг
04
Ожидание, что НЕ условие вернёт строки с NULL — они отсекаются без явной проверки ЕСТЬ NULL

НЕ против В и НЕ В для списков значений

Для проверки вхождения в список в языке запросов есть оператор В: ГДЕ Склад В (&СписокСкладов). Обратное условие корректно записывается как ГДЕ НЕ Склад В (&СписокСкладов) — здесь НЕ является стандартной идиомой, и заменять её перечислением через <> не нужно: цепочка Склад <> С1 И Склад <> С2 И ... громоздка и не работает с параметром-списком.

Та же оговорка про NULL: НЕ Склад В (...) не вернёт строки, где склад не заполнен. Если пустой склад должен попасть в выборку, добавляйте ИЛИ Склад ЕСТЬ NULL.

Во встроенном языке аналогичная задача решается через массив или соответствие. Вместо длинной цепочки Если НЕ (Значение = "А" ИЛИ Значение = "Б") Тогда удобнее собрать массив допустимых значений и проверять Если Допустимые.Найти(Значение) = Неопределено Тогда — такой код проще расширять.

Способы выразить отрицание

НЕ перед условием

Универсально, обязательно для НЕ В и инверсии сложных выражений. Требует аккуратности со скобками и NULL

Прямое условие (<>, ЕСТЬ NULL)

Предпочтительно в запросах для простых сравнений: читаемее и дружелюбнее к индексам. Не подходит для списков и составных условий

Проверка через массив/соответствие в коде

Лучший вариант для множественных значений во встроенном языке: легко расширять, нет длинных цепочек ИЛИ

НЕ во встроенном языке: читаемость условий

В модулях выбор между НЕ и альтернативой — это вопрос стиля и ясности. Хорошие паттерны: Если НЕ Отказ Тогда, Если НЕ ЗначениеЗаполнено(Ссылка) Тогда. Они коротки и соответствуют устоявшейся практике.

Плохие паттерны: Если НЕ Флаг = Истина Тогда (избыточно, достаточно НЕ Флаг), Если Флаг = Ложь Тогда (допустимо, но НЕ Флаг короче), двойные отрицания и инверсия функций с говорящими именами. Если функция называется ЭтоДоступно(), то НЕ ЭтоДоступно() читается нормально, а вот для НЕ Недоступно() лучше переименовать метод, чем наращивать отрицания.

Практическое правило: если после инверсии условие приходится «переворачивать в уме» больше одного раза, переформулируйте его напрямую. Код читают чаще, чем пишут, и лишняя инверсия — частый источник ошибок при доработках.

Отрицание в отборах СКД и динамических списков

В настройках отбора (отчёты на СКД, динамические списки) вместо НЕ используются виды сравнения: «Не равно», «Не в списке», «Не заполнено». Это предпочтительный путь: пользовательский отбор с видом «Не равно» прозрачен, отображается в настройках и корректно транслируется в запрос.

Ошибка — прятать отрицание в произвольное условие на языке запросов внутри СКД, когда задача решается стандартным видом сравнения. Такое условие невидимо для пользователя в настройках отчёта, и при расследовании «почему пропали данные» его найдут в последнюю очередь.

Для проверки незаполненности используйте вид сравнения «Не заполнено», а не сравнение с пустой ссылкой через НЕ: он корректно обрабатывает и NULL, и пустые значения разных типов.

Маршрут решения

Как выбрать вариант

Простое сравнение поля со значением в запросеИспользуйте <> вместо НЕ ... =
Проверка отсутствия значения в спискеИспользуйте НЕ ... В (&Параметр), при необходимости добавьте ИЛИ ЕСТЬ NULL
Инверсия сложного условия из 2–3 частейРаскройте по правилам де Моргана, если это улучшает читаемость
Отбор в отчёте СКД или динамическом спискеИспользуйте вид сравнения Не равно / Не в списке, а не НЕ в тексте запроса
Условие в коде модуляНЕ допустимо, но без двойных отрицаний и лишних сравнений с Истина/Ложь

Проверка результата и производительность

После замены НЕ на прямое условие (или наоборот) обязательно сравните результат на реальных данных, включая записи с незаполненными полями. Самый надёжный способ — выполнить оба варианта запроса в консоли запросов и сверить количество строк и контрольные суммы по ключевым полям.

Если запрос работает с большими таблицами, посмотрите план запроса в консоли СУБД или через технологический журнал: условие, блокирующее использование индекса, на больших объёмах превращается в полное сканирование таблицы. Прямое условие <> в этом смысле обычно предсказуемее, чем НЕ поверх составного выражения.

Контрольные точки

Как проверить корректность замены

Количество строк результата
Норма

Совпадает со старым вариантом на тестовых данных

Тревожный признак

Различается — вероятно, проблема с NULL или приоритетом операторов

Строки с незаполненными полями
Норма

Поведение явно задано через ЕСТЬ NULL и подтверждено выборкой

Тревожный признак

Строки с NULL пропадают незаметно

План запроса на большой таблице
Норма

Используется индекс по полю отбора

Тревожный признак

Полное сканирование таблицы

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

Итог

Что важно запомнить

НЕ и прямое условие не всегда взаимозаменяемы: при NULL оба отсекают строки, а приоритет НЕ требует скобок. В запросах предпочитайте <>, для списков — НЕ В, в СКД — виды сравнения, в коде — НЕ без лишних сравнений с Истина.

Частые вопросы

Чем отличается НЕ во встроенном языке от НЕ в запросе?

Во встроенном языке это простой логический оператор над булевым значением, выполняемый интерпретатором. В запросе условие транслируется в SQL, где действует трёхзначная логика: сравнение с NULL даёт неопределённость, и строка отсекается. Поэтому в запросах НЕ требует дополнительной проверки на NULL.

Почему запрос с условием НЕ Поле = Значение не вернул строки с пустым полем?

Потому что для NULL сравнение «равно» не даёт Истину, а значит, и его отрицание не даёт Истину — результат неопределён, строка отсекается. Добавьте в условие ИЛИ Поле ЕСТЬ NULL, если такие строки нужны.

Влияет ли замена НЕ на <> на скорость запроса?

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

Нужно ли писать скобки в условии НЕ А И Б?

Да, если хотите инвертировать всё выражение: без скобок НЕ применится только к А, потому что у него наивысший приоритет. Записывайте НЕ (А И Б) явно — это и надёжнее, и понятнее при чтении.

Как в отчёте на СКД исключить конкретное значение без правки запроса?

Добавьте в настройках отбор по полю с видом сравнения «Не равно» и укажите значение. Для списка значений используйте «Не в списке». Это видно пользователю в настройках и не требует изменения текста запроса.

Что лучше: Если Флаг = Ложь или Если НЕ Флаг?

Оба варианта корректны, но НЕ Флаг короче и считается более идиоматичным. Сравнение с Ложь оправдано только там, где переменная может быть не булевой и нужна строгая проверка типа значения.