Работа с NULL-значениями в запросах 1С:Предприятие — одна из самых распространённых головных болей разработчиков. Даже опытные программисты иногда путают, как правильно отфильтровать пустые значения, чтобы не потерять данные или, наоборот, не получить лишние строки. Проблема усугубляется тем, что синтаксис отличается от стандартного SQL, а поведение операторов = NULL, <> NULL и ЕСТЬ NULL не всегда интуитивно понятно.

В этой статье разберём все способы работы с NULL в запросах 1С 8.3: от базового синтаксиса до оптимизации сложных выборок. Вы узнаете, почему ГДЕ Поле = NULL не работает, как правильно комбинировать условия с ЕСТЬNULL(), и какие подводные камни ждут при работе с пустыми ссылками, датами и числами. Особое внимание уделим типичным ошибкам, которые приводят к некорректным результатам или падению производительности.

Если вы когда-нибудь сталкивались с ситуацией, когда запрос внезапно возвращает не те данные из-за незаполненных полей — эта статья поможет разобраться в причинах и избежать подобных проблем в будущем.

Почему NULL в 1С ведёт себя не как пустая строка

Многие разработчики ошибочно считают, что NULL в эквивалентен пустой строке ("") или нулю (0). На самом деле NULL — это маркер отсутствия значения, а не само значение. Это принципиальное отличие влияет на логику работы операторов сравнения.

Вот ключевые особенности:

  • 🔹 NULL ≠ пустой строке: поле с NULL не равно полю с "", даже если визуально они выглядят одинаково.
  • 🔹 NULL ≠ нулю: для числовых полей NULL не то же самое, что 0.
  • 🔹 NULL ≠ отсутствию записи: если поле не включено в запрос, это не значит, что оно содержит NULL.
  • 🔹 Логические операции с NULL: выражение NULL = NULL возвращает не Истина, а Неопределено.

Из-за этих нюансов стандартные операторы сравнения (=, <>, >) не работают с NULL так, как ожидается. Например, запрос:

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ ДатаОплаты = NULL

никогда не вернёт ни одной строки, даже если поле ДатаОплаты не заполнено в половине документов.
📊 Как вы обычно фильтруете NULL в запросах 1С?
Использую ЕСТЬ NULL
Пишу <> NULL
Применяю ЕСТЬNULL()
Другое

Базовый синтаксис: ЕСТЬ NULL и ЕСТЬ NULL НЕ

Для корректной фильтрации NULL в предназначены специальные операторы:

  • 🔍 ЕСТЬ NULL — проверяет, что поле содержит NULL.
  • 🔍 ЕСТЬ NULL НЕ (или <> NULL) — проверяет, что поле не содержит NULL.

Примеры использования:

// Найти документы без даты оплаты

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ ДатаОплаты ЕСТЬ NULL

// Найти документы с заполненной датой оплаты

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ ДатаОплаты ЕСТЬ NULL НЕ

Обратите внимание: оператор <> NULL работает так же, как ЕСТЬ NULL НЕ, но первый вариант менее читаемый и может сбивать с толку.

💡

Если вам нужно проверить несколько полей на NULL одновременно, используйте конструкцию ГДЕ (Поле1 ЕСТЬ NULL) И (Поле2 ЕСТЬ NULL). Это эффективнее, чем проверять каждое поле отдельно в разных запросах.

Работа с пустыми ссылками и объектами

Особую сложность представляют пустые ссылки (например, на справочники или документы). В пустая ссылка — это не то же самое, что NULL в числовых или строковых полях. Для их проверки используются те же операторы ЕСТЬ NULL, но с учётом типа данных.

Пример с справочником Контрагенты:

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ Контрагент ЕСТЬ NULL // Найти заказы без указанного контрагента

Важно: если поле является ссылкой на объект, но не содержит NULL, а просто не заполнено (например, пользователь не выбрал значение в форме), оно всё равно может участвовать в выборке как "пустое". В этом случае лучше использовать конструкцию:

ГДЕ НЕ Контрагент.ЭтоГруппа() И Контрагент ЕСТЬ NULL
Что будет, если сравнить пустую ссылку с непустой?

При сравнении пустой ссылки (NULL) с любой непустой ссылкой результат всегда будет Ложь, даже если визуально они "пустые". Например, ПустаяСсылка = НепустаяСсылка.Пустая() вернёт Ложь, а не Истина.

Комбинация с другими условиями: AND, OR, NOT

При построении сложных запросов с NULL важно правильно комбинировать условия. Например, если нужно найти документы, где или дата оплаты не заполнена, или сумма меньше 1000, запрос будет выглядеть так:

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ (ДатаОплаты ЕСТЬ NULL)

ИЛИ (СуммаДокумента < 1000)

Обратите внимание на скобки: они обязательны, чтобы избежать неоднозначности в приоритете операторов. Без скобок запрос может интерпретироваться некорректно, особенно если условия смешаны с И и ИЛИ.

Типичная ошибка — попытка использовать НЕ с NULL без оператора ЕСТЬ:

// НЕПРАВИЛЬНО! Не вернёт ожидаемый результат

ГДЕ НЕ ДатаОплаты = NULL

// ПРАВИЛЬНО

ГДЕ ДатаОплаты ЕСТЬ NULL НЕ

☑️ Проверка корректности запроса с NULL

Выполнено: 0 / 4

Функция ЕСТЬNULL() и её аналоги

Для замены NULL на другое значение в выборке используется функция ЕСТЬNULL(). Она аналогична ISNULL() в T-SQL или COALESCE() в стандартном SQL, но с синтаксисом :

ВЫБРАТЬ

ЕСТЬNULL(ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОплатыПодстановка

ИЗ Документ.ЗаказКлиента

Функция принимает два аргумента:

  1. Поле, которое может содержать NULL.
  2. Значение для подстановки, если поле содержит NULL.

Важные нюансы:

  • 📌 ЕСТЬNULL() работает только в списке выборки, но не в условиях ГДЕ.
  • 📌 Для ссылочных полей в качестве замены можно использовать ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка()).
  • 📌 Если второй аргумент тоже NULL, функция вернёт NULL.

Альтернатива — функция ВЫРАЗИТЬ(), которая позволяет более гибко обрабатывать NULL:

ВЫБРАТЬ

ВЫРАЗИТЬ(ДатаОплаты КАК ДАТА) КАК КорректнаяДата

ИЗ Документ.ЗаказКлиента

💡

Функция ЕСТЬNULL() не влияет на производительность запроса, но её чрезмерное использование может усложнить поддержку кода. Применяйте её только там, где действительно нужно подставить значение вместо NULL.

Оптимизация запросов с NULL: индексы и план выполнения

Запросы с проверкой на NULL могут работать медленно, если:

  • 🐢 Поле, проверяемое на NULL, не проиндексировано.
  • 🐢 В таблице много строк с NULL в этом поле.
  • 🐢 Условие с NULL комбинируется с другими сложными фильтрами.

Рекомендации по оптимизации:

  1. Добавьте индекс на поля, которые часто проверяются на NULL (через конфигуратор или программно).
  2. Избегайте конструкций вида ГДЕ (Поле1 ЕСТЬ NULL) ИЛИ (Поле2 ЕСТЬ NULL) — они могут привести к полному сканированию таблицы.
  3. Если возможно, разделите запрос на два отдельных (с NULL и без) и объедините результаты с помощью ОБЪЕДИНИТЬ ВСЕ.

Пример оптимизированного запроса:

// Вместо одного сложного запроса:

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ (ДатаОплаты ЕСТЬ NULL) ИЛИ (СуммаДокумента > 10000)

// Лучше сделать так:

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ ДатаОплаты ЕСТЬ NULL

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ *

ИЗ Документ.ЗаказКлиента

ГДЕ СуммаДокумента > 10000

И ДатаОплаты ЕСТЬ NULL НЕ

Для анализа производительности используйте план выполнения запроса в конфигураторе (Отладка → План запроса). Это поможет выявить "бутылочные горлышки".

💡

Если запрос с NULL выполняется слишком долго, попробуйте временно убрать условие с NULL и посмотрите, как изменится время выполнения. Это поможет понять, является ли NULL основной причиной тормозов.

Типичные ошибки и как их избежать

Даже опытные разработчики допускают ошибки при работе с NULL. Вот самые распространённые:

Ошибка Пример кода Правильный вариант
Использование = NULL ГДЕ Поле = NULL ГДЕ Поле ЕСТЬ NULL
Путаница с "" и NULL ГДЕ Поле = "" ГДЕ (Поле = "") ИЛИ (Поле ЕСТЬ NULL)
Некорректное использование НЕ ГДЕ НЕ Поле = NULL ГДЕ Поле ЕСТЬ NULL НЕ
Пропуск скобок в сложных условиях ГДЕ Поле1 ЕСТЬ NULL ИЛИ Поле2 > 100 И Поле3 = "Текст" ГДЕ (Поле1 ЕСТЬ NULL) ИЛИ (Поле2 > 100 И Поле3 = "Текст")

Ещё одна частая проблема — неявное преобразование типов. Например, если поле имеет тип Число, но в нём хранится NULL, то сравнение с 0 не даст ожидаемого результата:

// НЕ сработает для NULL!

ГДЕ Поле = 0

// Правильно:

ГДЕ (Поле = 0) ИЛИ (Поле ЕСТЬ NULL)

Почему запрос с NULL может возвращать дубли?

Если в выборке участвуют таблицы с соединением ЛЕВОЕ или ПОЛНОЕ, поля из "правой" таблицы, для которых нет соответствий, будут содержать NULL. Это может привести к дублированию строк, если не учесть NULL в условиях.

Практические примеры: от простого к сложному

Разберём несколько реальных сценариев работы с NULL в .

Пример 1: Поиск документов без прикреплённых файлов

ВЫБРАТЬ

Ссылка КАК Документ,

ВИД() КАК ТипДокумента

ИЗ Документ.ЛюбойДокумент

ГДЕ Файлы ЕСТЬ NULL

Пример 2: Подсчёт количества заказов с оплатой и без

ВЫБРАТЬ

ЕСТЬNULL(ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) КАК ДатаОплаты,

КОЛИЧЕСТВО(*) КАК Количество

ИЗ Документ.ЗаказКлиента

СГРУППИРОВАТЬ ПО

ЕСТЬNULL(ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1))

Пример 3: Комплексный запрос с несколькими NULL-полями

ВЫБРАТЬ

Контрагент.Наименование КАК Клиент,

ЕСТЬNULL(ДатаОплаты, ДАТАВРЕМЯ(1, 1, 1)) КАК Оплата,

СуммаДокумента КАК Сумма

ИЗ Документ.ЗаказКлиента КАК Заказ

ЛЕВОЕ СОЕДИНЕНИЕ Справочник.Контрагенты КАК Контрагент

ПО Заказ.Контрагент = Контрагент.Ссылка

ГДЕ (Заказ.ДатаОплаты ЕСТЬ NULL)

И (Контрагент.ИНН ЕСТЬ NULL НЕ)

И (Заказ.СуммаДокумента > 5000)

В последнем примере важно обратить внимание на:

  • 🔸 Использование ЛЕВОЕ СОЕДИНЕНИЕ, которое может порождать NULL в полях справочника.
  • 🔸 Комбинацию условий с NULL и без него.
  • 🔸 Подстановку значения вместо NULL в выборке (ЕСТЬNULL).
💡

При работе с LEFT JOIN (ЛЕВОЕ СОЕДИНЕНИЕ) всегда проверяйте поля из "правой" таблицы на NULL, даже если логически они не должны быть пустыми. Это поможет избежать ошибок в расчётах.

⚠️ Внимание: Если вы используете управляемые формы в 1С 8.3, учтите, что при программном формировании запросов через Запрос.Текст синтаксис остаётся тем же, но могут возникать ошибки при динамическом построении условий. Всегда проверяйте итоговый текст запроса перед выполнением.

FAQ: Частые вопросы по работе с NULL в 1С

Почему запрос с условием Поле = NULL не возвращает строк, хотя в таблице есть пустые значения?

Потому что NULL — это не значение, а маркер его отсутствия. В (как и в стандартном SQL) выражение NULL = NULL возвращает Неопределено, а не Истина. Для проверки на NULL нужно использовать оператор ЕСТЬ NULL.

Как отличить пустую строку ("") от NULL?

Пустая строка — это значение, а NULL — его отсутствие. Чтобы найти и то, и другое, используйте:

ГДЕ (Поле = "") ИЛИ (Поле ЕСТЬ NULL)

Если нужно найти только непустые строки (исключая NULL и ""):

ГДЕ (Поле <> "") И (Поле ЕСТЬ NULL НЕ)
Можно ли использовать NULL в вычисляемых полях?

Да, но с осторожностью. Например, если одно из полей в выражении содержит NULL, результат всего выражения тоже будет NULL:

ВЫБРАТЬ

(Поле1 + Поле2) КАК Сумма // Если Поле1 или Поле2 = NULL, то Сумма = NULL

ИЗ Таблица

Чтобы избежать этого, используйте ЕСТЬNULL():

ВЫБРАТЬ

ЕСТЬNULL(Поле1, 0) + ЕСТЬNULL(Поле2, 0) КАК Сумма

ИЗ Таблица

Как найти записи, где хотя бы одно из нескольких полей содержит NULL?

Используйте конструкцию с ИЛИ:

ГДЕ (Поле1 ЕСТЬ NULL)

ИЛИ (Поле2 ЕСТЬ NULL)

ИЛИ (Поле3 ЕСТЬ NULL)

Если полей много, можно сформировать условие динамически в цикле.

Почему после обновления запросы с NULL стали работать медленнее?

Это может быть связано с:

  1. Изменением плана выполнения запросов в новой версии платформы.
  2. Отсутствием актуальных статистик (пересчитайте их через Тестирование и исправление → Пересчитать статистики).
  3. Добавлением новых индексов, которые конфликтуют с условиями на NULL.

Проверьте план выполнения запроса и при необходимости добавьте подсказки (ИНДЕКСИРОВАТЬ ПО).