Как узнать, заполнен ли реквизит или поле в 1С
Содержание
В запросе пустое поле проверяют оператором ЕСТЬ NULL, во встроенном языке — функцией ЗначениеЗаполнено(). Это два разных механизма, и путать их нельзя: в запросе отсутствие строки после соединения даёт NULL, а в коде пустая ссылка на справочник — это не NULL, а валидное «пустое» значение своего типа.
Разберём оба контекста и заодно третий случай, который чаще всего и ломает логику, — реквизит составного типа, где нужно сначала понять, какой тип там лежит, и только потом проверять.
Примеры даны для платформы 8.3 и языка запросов 1С. Код одинаков во всех типовых конфигурациях (БП 3.0, ЗУП 3.1, УТ 11) — это механизм платформы, а не прикладного решения.
Три разных «пустых» значения и почему их путают
Прежде чем проверять, надо понять, что именно вы ищете. В 1С «не заполнено» — это не одно состояние, а минимум три:
- 🔹 Пустая ссылка — реквизит типа «СправочникСсылка» или «ДокументСсылка», в который ничего не выбрали. Это полноценное значение своего типа, просто «нулевое». В базе оно хранится как ссылка с пустым GUID.
- 🔹 NULL — отсутствие значения как такового. В таблицах базы данных его почти не бывает; он возникает в результате запроса, когда левое или полное соединение не нашло пары, либо когда обращаетесь к несуществующему реквизиту через точку.
- 🔹 Неопределено — значение встроенного языка, которое означает «тип и значение не заданы». Встречается в реквизитах составного типа и при работе с коллекциями.
Плюс к этому «пустыми» по смыслу считаются пустая строка, число 0, пустая дата ('00010101') и False.
Главное правило: NULL живёт в запросах, пустая ссылка — в полях объектов, Неопределено — во встроенном языке. Инструмент проверки выбирают под то, что именно может прийти.
Оператор ЕСТЬ NULL в языке запросов
В языке запросов для проверки на отсутствие значения есть оператор ЕСТЬ NULL (и обратный ЕСТЬ НЕ NULL). Сравнивать через = NULL нельзя — такое условие всегда ложно, потому что NULL не равен ничему, даже самому себе.
ВЫБРАТЬ
Заказы.Ссылка,
Заказы.Контрагент
ИЗ
Документ.ЗаказПокупателя КАК Заказы
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Оплаты КАК Оплаты
ПО Оплаты.Заказ = Заказы.Ссылка
ГДЕ
Оплаты.Заказ ЕСТЬ NULL
Здесь мы находим заказы, по которым нет ни одной записи об оплате: левое соединение подставило NULL в поля несуществующих строк, и ЕСТЬ NULL их отлавливает.
NULL возникает и в другой ситуации — при обращении через точку к реквизиту пустой или несуществующей ссылки. Если в поле Контрагент пустая ссылка, то Заказы.Контрагент.ИНН в запросе вернёт не пустую строку, а NULL. Поэтому цепочки через точку в запросах тоже защищают оператором ЕСТЬ NULL или оборачивают в ЕСТЬNULL(...) — иначе условие по такому полю молча отбросит нужные строки.
Когда NULL нужно не отфильтровать, а заменить на осмысленное значение, применяют функцию ЕСТЬNULL(Выражение, ЗначениеПоУмолчанию). Она возвращает первый аргумент, если он не NULL, иначе второй:
ВЫБРАТЬ
Заказы.Ссылка,
ЕСТЬNULL(СУММ(Оплаты.Сумма), 0) КАК СуммаОплат
ИЗ
Документ.ЗаказПокупателя КАК Заказы
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.Оплаты.Остатки КАК Оплаты
ПО Оплаты.Заказ = Заказы.Ссылка
СГРУППИРОВАТЬ ПО
Заказы.Ссылка
Без ЕСТЬNULL сумма по заказам без оплат пришла бы как NULL, и любая последующая арифметика с ней дала бы снова NULL. Арифметика с NULL всегда возвращает NULL — одно необёрнутое поле портит всю сумму в отчёте.
Отдельный случай — пустая ссылка. Она не NULL, поэтому ЕСТЬ NULL её не поймает. Чтобы отобрать строки с незаполненной ссылкой, сравнивают с пустым значением типа:
ГДЕ
Заказы.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
Проверка полей составного типа
Реквизит составного типа (например, «Основание» у документа или «Значение» в регистре сведений) может хранить ссылки на разные справочники и документы. Прежде чем что-то с ним делать, нужно выяснить, что именно в нём лежит.
В запросе тип определяют через выражение ВЫРАЗИТЬ(Поле КАК Тип): если поле другого типа, приведение вернёт NULL.
ВЫБРАТЬ
Движения.Регистратор,
ВЫРАЗИТЬ(Движения.Аналитика КАК Справочник.Контрагенты) КАК Контрагент
ИЗ
РегистрНакопления.Взаиморасчёты КАК Движения
ГДЕ
ВЫРАЗИТЬ(Движения.Аналитика КАК Справочник.Контрагенты) ЕСТЬ НЕ NULL
Так остаются только те записи, где в составном поле «Аналитика» лежит именно контрагент. Остальные типы ВЫРАЗИТЬ превратило в NULL, а ЕСТЬ НЕ NULL их отсеял.
Во встроенном языке тип значения из составного поля узнают функцией ТипЗнч():
Если ТипЗнч(Движение.Аналитика) = Тип("СправочникСсылка.Контрагенты") Тогда
// работаем с контрагентом
КонецЕсли;
Если составное поле не заполнено, во встроенном языке в нём будет Неопределено, а не пустая ссылка конкретного справочника. Поэтому проверка Поле = Справочники.Контрагенты.ПустаяСсылка на составном типе может не сработать так, как ожидаете, — надёжнее ЗначениеЗаполнено().
Как собрать условие в конструкторе запросов
Руками оператор ЕСТЬ NULL писать не обязательно — его ставит конструктор запроса.
- В модуле откройте контекстное меню на тексте запроса →
Конструктор запроса(или начните с пустогоЗапрос.Текст = ""и вызовите конструктор из команды). - Перенесите нужную таблицу в область
Таблицы, выберите поля. - Перейдите на закладку
Условия. - Включите флажок
Произвольноеу новой строки условия — поле ввода станет доступным для ручного текста. - Впишите выражение вида
ТаблицаЗаказы.Контрагент ЕСТЬ NULLили с функциейЕСТЬNULL(...).
Для простого сравнения с пустой ссылкой флажок Произвольное не нужен: перетащите поле в условие, в правой части выберите значение и оставьте его пустым — конструктор сам подставит = ЗНАЧЕНИЕ(...ПустаяСсылка).
Проверка значения во встроенном языке
В коде отдельного оператора для «заполненности» нет — есть универсальная функция ЗначениеЗаполнено(). Она возвращает Ложь для любого пустого значения: пустой ссылки, пустой строки, числа 0, пустой даты, Неопределено, NULL и False.
Если НЕ ЗначениеЗаполнено(Объект.Контрагент) Тогда
Сообщить("Не выбран контрагент");
Возврат;
КонецЕсли;
Это основной способ проверить реквизит документа или объекта перед записью, расчётом или печатью. Он один корректно обрабатывает все типы сразу, поэтому отдельно сравнивать с пустой ссылкой нужно редко.
У функции есть нюансы, о которых стоит помнить. Строка из одних пробелов считается заполненной — ЗначениеЗаполнено() смотрит на длину, а не на содержимое; если нужно отсечь и пробелы, сначала примените СокрЛП(). Дата '00010101' (минимально возможная) считается пустой, а вот любая реальная дата, даже «нулевая» по смыслу, — заполненной. Для булева значения Ложь функция вернёт Ложь, поэтому флаги так не проверяют — их читают напрямую условием Если Объект.Проведён Тогда.
Когда проверок много и они описаны в метаданных, вместо ручных Если вызывают метод объекта ПроверитьЗаполнение():
Если НЕ Объект.ПроверитьЗаполнение() Тогда
Отказ = Истина;
Возврат;
КонецЕсли;
Метод обходит все реквизиты, у которых в конфигураторе задано свойство Проверка заполнения = Выдавать ошибку, и сам выводит сообщения об ошибках у незаполненных полей. Для табличных частей проверка срабатывает построчно.
Свой сценарий проверки добавляют в обработчик ОбработкаПроверкиЗаполнения модуля объекта — там дописывают условия, которые нельзя задать флажком в конфигураторе (например, «поле обязательно, только если установлен другой флаг»).
На форме пустой обязательный реквизит удобно подсвечивать автоматически: у элемента формы есть свойство АвтоОтметкаНезаполненного. Платформа сама обведёт поле красным, если оно участвует в проверке заполнения.
Отладка: почему реквизит остаётся пустым
Если значение упорно приходит пустым, нужен отладчик. Порядок поиска такой:
- Поставьте точку останова (
F9) на строке, где значение уже должно быть заполнено. - Запустите в режиме отладки (
F5); когда выполнение остановится, откройте окноТаблои перетащите туда интересующий реквизит. - Или выделите выражение и нажмите
Shift+F9—Вычислить выражениепокажет текущее значение и его тип. - Пройдите по шагам (
F11— с заходом в процедуры,F10— без) и посмотрите, на каком шаге значение теряется.
Чаще всего пустое поле объясняется одной из типовых причин:
ТипЗнч() посмотрите фактический тип и приводите ВЫРАЗИТЬ именно к нему.ЕСТЬNULL(..., 0).ОбработкаЗаполнения или начальное заполнение реквизита не отработали для этого способа создания объекта (ввод на основании, копирование, обмен).Если значение корректно в отладчике, но пустое в печатной форме или отчёте, ищите ошибку уже в макете или в тексте запроса компоновки, а не в самом реквизите.
Отбор по заполненности в отчёте на СКД
В системе компоновки данных отдельно писать ЕСТЬ NULL не нужно — там для этого есть готовые виды сравнения. На закладке Отборы в настройках отчёта (или в схеме компоновки) выберите поле и в колонке Вид сравнения укажите Заполнено или Не заполнено.
Эти два вида сравнения корректно учитывают все варианты «пустого» сразу: и NULL, и пустую ссылку, и пустую строку. Это удобнее, чем ручное условие, потому что не надо помнить, что именно придёт по конкретному полю.
Если же поле в отчёте нужно не отфильтровать, а показать с подстановкой («—» вместо пустого), задайте в макете или в вычисляемом поле выражение с функцией ЕстьNULL — в выражениях СКД работает та же логика, что и в запросе.
Когда в отчёте по остаткам появляются пустые ячейки вместо нулей, причина почти всегда в соединении таблиц внутри набора данных. Разворачивать отладчик не нужно — достаточно обернуть ресурс в ЕСТЬNULL(..., 0) прямо в запросе набора данных.
Сводная таблица: чем проверять в разных контекстах
| Контекст | Что проверяем | Инструмент |
|---|---|---|
| Запрос, отсутствие строки после соединения | NULL | ЕСТЬ NULL / ЕСТЬ НЕ NULL |
| Запрос, замена NULL на значение | NULL → число/строка | ЕСТЬNULL(Поле, 0) |
| Запрос, незаполненная ссылка | пустая ссылка | = ЗНАЧЕНИЕ(...ПустаяСсылка) |
| Запрос, составной тип | какой тип в поле | ВЫРАЗИТЬ(Поле КАК Тип) |
| Встроенный язык, любой реквизит | любое пустое значение | ЗначениеЗаполнено() |
| Встроенный язык, тип составного поля | конкретный тип | ТипЗнч() |
| Объект целиком перед записью | все обязательные реквизиты | ПроверитьЗаполнение() |
Запомнить проще по контексту: в запросе отправная точка — NULL, в коде — ЗначениеЗаполнено(), а для составных типов сначала всегда определяют тип и только потом проверяют значение.
Частые вопросы
Чем `ЕСТЬ NULL` отличается от `ЗначениеЗаполнено()`?
ЕСТЬ NULL — оператор языка запросов, ловит именно NULL в результате выборки. ЗначениеЗаполнено() — функция встроенного языка, возвращает Ложь для любого пустого значения, включая пустую ссылку и пустую дату. В запросе вторую применить нельзя, в коде первую — тоже.Почему условие `Поле = NULL` в запросе не работает?
NULL не равен ничему, даже другому NULL, поэтому сравнение всегда даёт «ложь» и ни одной строки не вернёт. Для проверки на NULL есть только оператор ЕСТЬ NULL.Пустая ссылка и `NULL` — это одно и то же?
NULL — отсутствие значения, появляется в результатах запросов. ЕСТЬ NULL не поймает пустую ссылку, а ЗначениеЗаполнено() считает пустым и то, и другое.Как проверить заполнение всех обязательных реквизитов разом?
ПроверитьЗаполнение(). Он проверит все реквизиты со свойством Проверка заполнения = Выдавать ошибку и сам покажет сообщения у пустых полей. Дополнительные условия дописывают в обработчик ОбработкаПроверкиЗаполнения.Как узнать, какой тип лежит в реквизите составного типа?
ТипЗнч(Значение) и сравнением с Тип("СправочникСсылка.Контрагенты"). В запросе — приведением ВЫРАЗИТЬ(Поле КАК Тип): если тип не совпал, получите NULL.