Работа с пустыми значениями в языке запросов платформы 1С:Предприятие 8.3 и выше часто вызывает затруднения у разработчиков, особенно тех, кто переходит с предыдущих версий платформы или из других языков программирования. В отличие от SQL, где NULL — это отсутствие значения, в запросах 1С понятие пустоты трактуется специфически. Разработчики часто сталкиваются с ситуацией, когда выборка возвращает лишние записи или, наоборот, теряет нужные данные из-за некорректной фильтрации полей типа "СправочникСсылка" или "ДокументСсылка".

Основная проблема кроется в том, что пустая ссылка в базе данных 1С технически может храниться как NULL, но язык запросов требует явного приведения типов или использования специальных конструкций для корректной обработки таких ситуаций. Если вы попробуете написать условие Где Справочник = NULL, система выдаст ошибку синтаксиса или логическую ошибку выполнения. Понимание механизмов обработки пустых значений критически важно для написания производительных отчетов и обработок данных.

В данной статье мы детально разберем все легальные способы исключения записей с пустыми ссылками из результата выборки. Мы рассмотрим как классические подходы с использованием константы ИСТИНА, так и более современные методы с применением таблиц значений и временных таблиц. Правильная фильтрация не только очистит ваши отчеты от "мусора", но и существенно ускорит выполнение запросов за счет оптимального использования индексов.

Природа пустых значений в платформе 1С

В основе платформы 1С:Предприятие лежит строгая типизация данных. Поля табличных частей документов или регистров сведений, имеющие тип "СправочникСсылка", по умолчанию могут быть пустыми. Однако, в контексте языка запросов, понятие "пусто" не тождественно SQL-ному NULL в чистом виде, хотя на уровне СУБД (например, Microsoft SQL Server или PostgreSQL) оно часто мапится именно так. Платформа 1С абстрагирует разработчика от прямого взаимодействия с NULL, предлагая свои механизмы проверки.

Когда вы формируете запрос через конфигуратор или в коде, система пытается автоматически привести типы. Если поле содержит пустую ссылку, попытка сравнить его с конкретным элементом справочника без предварительной проверки приведет к тому, что запись просто не попадет в выборку при использовании оператора =. Однако, при использовании оператора <> (не равно) логика может вести себя неочевидно для новичка. Пустая ссылка требует явного указания условия отбора.

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

⚠️ Внимание: Никогда не полагайтесь на неявное приведение типов в сложных запросах с объединениями (UNION ALL). Если в одной части объединения поле заполнено, а в другой — пусто, это может вызвать ошибку типов при выполнении запроса на уровне СУБД.

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

Классический метод: использование ИСТИНА

Самый распространенный и исторически первый способ убрать записи с пустыми значениями — это использование условия ИСТИНА. В языке запросов 1С константа ИСТИНА (или TRUE в английской локали) выступает в роли универсального заполнителя, который никогда не равен пустой ссылке. Логика здесь проста: мы говорим системе, что поле должно быть равно некому существующему значению, которое заведомо не является пустотой.

Синтаксически это выглядит как сравнение поля с константой. Например, если у нас есть поле Номенклатура, условие будет выглядеть так: Где Номенклатура = ИСТИНА. Это условие отсечет все записи, где ссылка пуста, и оставит только те, где указан конкретный элемент справочника. Данный метод работает быстро и поддерживается во всех версиях платформы без исключения.

Однако у этого подхода есть один нюанс, о котором стоит знать. Использование ИСТИНА иногда может сбить с толку при чтении кода коллегами, которые не знакомы с этим трюком. Кроме того, в некоторых редких случаях при сложной оптимизации запросов сервер 1С может генерировать менее оптимальный план выполнения по сравнению с явными таблицами значений, хотя на практике разница чаще всего незаметна.

💡

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

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

ВЫБРАТЬ

ПоступлениеТоваровУслуг.Ссылка КАК Ссылка,

ПоступлениеТоваровУслуг.Номенклатура КАК Номенклатура

ИЗ

Документ.ПоступлениеТоваровУслуг КАК ПоступлениеТоваровУслуг

ГДЕ

ПоступлениеТоваровУслуг.Номенклатура = ИСТИНА

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

Современный подход: Таблица значений и параметры

Более гибким и читаемым способом, который рекомендуют эксперты по разработке на 1С в последнее время, является использование конструкции В (&Параметр) с передачей таблицы значений. Этот метод позволяет явно перечислить допустимые значения или, наоборот, создать таблицу с одним значением ИСТИНА и использовать её для фильтрации. Такой подход делает код самодокументируемым.

Суть метода заключается в том, что мы создаем в коде 1С объект ТаблицаЗначений, добавляем в него колонку с нужным типом (например, СправочникСсылка.Номенклатура) и заполняем её значением ИСТИНА. Затем эта таблица передается в запрос как параметр. В тексте запроса мы пишем условие Где Поле В (&ПараметрТЗ). Это эквивалентно проверке на не пустоту, но выглядит гораздо понятнее для поддержки.

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

📊 Какой метод фильтрации вы используете чаще?
ИСТИНА в тексте запроса
Таблица значений в коде
ИСТИНА() в тексте запроса
Свой вариант

Пример реализации в коде встроенного языка:

ТЗ_Фильтр = Новый ТаблицаЗначений;

ТЗ_Фильтр.Колонки.Добавить("Значение", Тип("СправочникСсылка.Номенклатура"));

НоваяСтрока = ТЗ_Фильтр.Добавить();

НоваяСтрока.Значение = ИСТИНА;

Запрос = Новый Запрос;

Запрос.Текст = "ВЫБРАТЬ ... ГДЕ Номенклатура В (&Фильтр)";

Запрос.УстановитьПараметр("Фильтр", ТЗ_Фильтр);

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

Функция ИСТИНА() и её отличия

В новых версиях платформы 1С (начиная с 8.3.10 и выше) появилась возможность использования функции ИСТИНА() непосредственно в тексте запроса. На первый взгляд, это кажется полным аналогом константы ИСТИНА, но есть важные семантические различия, которые влияют на работу компилятора запросов.

Константа ИСТИНА — это литерал, значение, которое подставляется в запрос. Функция ИСТИНА() — это вызов встроенной функции языка запросов, которая возвращает значение типа Булево, приводимое к нужному типу ссылки. Использование функции позволяет избежать некоторых проблем с типизацией в сложных составных типах.

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

⚠️ Внимание: Не путайте функцию ИСТИНА() с логическим выражением 1=1. В языке запросов 1С нет прямого аналога SQL-ного "1=1" для бесконечного цикла или всегда истинного условия, используйте именно ИСТИНА или ИСТИНА().

Синтаксис использования функции выглядит следующим образом:

ВЫБРАТЬ

Справочник.Номенклатура.Ссылка КАК Ссылка

ИЗ

Справочник.Номенклатура КАК Справочник

ГДЕ

Справочник.Родитель = ИСТИНА()

Этот метод особенно удобен, когда вы генерируете текст запроса программно и хотите избежать проблем с экранированием или подстановкой параметров. Функция ИСТИНА() является частью стандартного синтаксиса языка запросов и поддерживается всеми современными СУБД, используемыми с 1С.

Обработка NULL в соединениях (JOIN)

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

При использовании ЛЕВОЕ СОЕДИНЕНИЕ, если для записи из левой таблицы не нашлось пары в правой, поля правой таблицы будут заполнены значениями по умолчанию (NULL для ссылок). Если вы примените условие Где ПраваяТаблица.Поле = ИСТИНА в секции ГДЕ основного запроса, вы фактически превратите левое соединение во внутреннее, отбросив все записи, где не было пары.

Чтобы корректно убрать NULL, возникшие из-за отсутствия соединения, но сохранить логику левого соединения для других целей, условие фильтрации нужно переносить в секцию И самого соединения. Это позволяет отфильтровать пустые результаты соединения, не затрагивая основную выборку, если это необходимо, или явно отобрать только те записи, где соединение состоялось.

Пример правильной структуры запроса с фильтрацией результата соединения:

ВЫБРАТЬ

Лево.Ссылка,

Право.Реквизит

ИЗ

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

ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.ЦеныНоменклатуры КАК Право

ПО Лево.Номенклатура = Право.Номенклатура

И Право.Период = &Период

И Право.Ссылка = ИСТИНА

В данном примере условие Право.Ссылка = ИСТИНА находится внутри условия соединения. Это гарантирует, что в выборку попадут только те заказы, для которых удалось найти цену. Записи без цены будут исключены из результата, но логика запроса останется прозрачной.

Почему условие в ГДЕ превращает LEFT JOIN в INNER?

Если вы напишете условие "Где Право.Поле = ИСТИНА" после левого соединения, то строки, где Право.Поле равно NULL (так как пары не нашлось), не пройдут фильтр. В итоге останутся только строки, где пара была найдена, что по эффекту равно внутреннему соединению.

Сравнение методов и таблица производительности

Выбор конкретного метода удаления NULL зависит от контекста задачи, версии платформы и личных предпочтений команды разработки. Чтобы систематизировать знания, приведем сравнительную таблицу основных подходов. Она поможет вам принять взвешенное решение при проектировании новых отчетов или обработок.

В таблице ниже представлены ключевые характеристики каждого метода: читаемость кода, производительность на больших объемах данных и гибкость настройки.

Метод Читаемость Производительность Гибкость
= ИСТИНА Средняя (требует знания специфики) Высокая Низкая (статичное условие)
= ИСТИНА() Высокая (явная функция) Высокая Средняя
В (&ТЗ) Очень высокая (прозрачная логика) Средняя/Высокая (зависит от размера ТЗ) Очень высокая (динамическая фильтрация)
ЕСТЬNULL() Низкая (редко используется для фильтрации) Низкая (может мешать индексам) Средняя

Как видно из таблицы, метод с таблицей значений (В (&ТЗ)) выигрывает в гибкости и читаемости, что делает его предпочтительным для сложных конфигураций с высокой ротацией разработчиков. Метод с константой ИСТИНА остается стандартом для быстрых, простых запросов, где важна максимальная лаконичность кода.

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

💡

Для высоконагруженных систем приоритетом является использование методов, позволяющих СУБД использовать индексы (ИСТИНА, ИСТИНА()), избегая функций над полями в условии WHERE.

Частые ошибки и рекомендации по оптимизации

Даже опытные разработчики иногда допускают ошибки при работе с пустыми значениями. Одна из самых распространенных ошибок — попытка сравнить поле со строкой "" (пустая строка). Для типов "СправочникСсылка" это не сработает, так как тип данных несовместим. Пустая ссылка и пустая строка — это разные сущности в типизированной системе 1С.

Еще одна ошибка заключается в игнорировании составных типов. Если поле имеет тип, например, СправочникСсылка.Номенклатура или Неопределено, то условие = ИСТИНА может потребовать явного приведения типа или использования функции ТИПЗНАЧЕНИЯ() для предварительной проверки, хотя в большинстве случаев 1С справляется с этим автоматически.

При оптимизации запросов всегда проверяйте план выполнения. Убедитесь, что условие фильтрации по пустым значениям не блокирует использование индексов. В большинстве случаев операторы сравнения с константами (=, <>) индексируются корректно, а вот использование функций в левой части условия может привести к деградации производительности.

⚠️ Внимание: В конфигурациях с включенным режимом "Безопасный режим" некоторые методы динамического формирования запросов могут быть ограничены. Всегда тестируйте код на рабочей копии базы с актуальными правами доступа.

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

☑️ Чек-лист проверки запроса на NULL

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

FAQ: Часто задаваемые вопросы

Можно ли использовать NULL напрямую в запросе 1С?

Нет, язык запросов 1С не поддерживает ключевое слово NULL в том виде, в котором оно используется в стандартном SQL. Попытка написать Где Поле = NULL приведет к ошибке синтаксиса. Необходимо использовать константу ИСТИНА, функцию ИСТИНА() или таблицу значений для фильтрации пустых ссылок.

В чем разница между ИСТИНА и ИСТИНА() в запросе?

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

Почему мой запрос с ЛЕВОЕ СОЕДИНЕНИЕ возвращает меньше строк, чем ожидается?

Скорее всего, вы поставили условие фильтрации по полю правой таблицы (проверку на = ИСТИНА) в секцию ГДЕ основного запроса, а не в условие самого соединения. Это превращает левое соединение во внутреннее, отбрасывая строки, где не нашлось пары. Перенесите условие в блок ПО ... И ....

Как проверить, что поле НЕ пустое, если у него составной тип?

Для составных типов лучше всего использовать таблицу значений с типом, соответствующим одному из возможных типов поля, или использовать функцию ИСТИНА(), которая обычно корректно обрабатывает составные типы ссылок. Также можно использовать конструкцию Где ТипЗначенияСтроки(Поле) <> "Неопределено", но это менее производительно.

Влияет ли удаление NULL на скорость работы отчета?

Да, влияет положительно. Фильтрация пустых значений на уровне запроса (в СУБД) уменьшает объем данных, передаваемых по сети и обрабатываемых в памяти клиента 1С. Кроме того, правильные условия фильтрации позволяют базе данных использовать индексы, что значительно ускоряет выборку из больших таблиц.