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