ЗначениеЗаполнено, Пустая(), ЕСТЬ NULL: чем и где ловить незаполненные данные в 1С 8.3
Содержание
Проверить пустое значение в 1С 8.3 проще всего функцией ЗначениеЗаполнено(Значение): она вернёт Ложь для пустой ссылки, нуля, пустой строки, пустой даты, Неопределено и Null. В запросе так не получится — там пустоту проверяют конструкцией Поле ЕСТЬ NULL, функцией ЕСТЬNULL() и сравнением с ЗНАЧЕНИЕ(...ПустаяСсылка).
Остальные способы нужны для частных случаев: строка из пробелов, «битая» ссылка на удалённый объект, реквизит составного типа, пустая табличная часть. Ниже каждый случай с рабочим кодом. Всё описанное относится к платформе 8.3 и не зависит от конфигурации: одинаково работает в БП 3.0, ЗУП 3.1, УТ 11 и самописных базах.
Функции ПустоеЗначение() в 1С 8.3 нет. Она была во встроенном языке 1С 7.7. Если переносите старый код, заменяйте её на ЗначениеЗаполнено() — и инвертируйте условие: ПустоеЗначение(Х) = 1 превращается в Не ЗначениеЗаполнено(Х).
Что 1С считает пустым значением для каждого типа
У каждого типа данных есть значение по умолчанию. Его и называют пустым: именно его получает новый реквизит, пока пользователь ничего не ввёл.
| Тип | Пустое значение | Как записать в коде |
|---|---|---|
| Число | 0 | 0 |
| Строка | строка нулевой длины | "" |
| Дата | 01.01.0001 00:00:00 | '00010101' или Дата(1, 1, 1) |
| Ссылка на справочник, документ | пустая ссылка | Справочники.Номенклатура.ПустаяСсылка() |
| Перечисление | пустая ссылка | Перечисления.СтавкиНДС.ПустаяСсылка() |
| Составной тип | Неопределено | Неопределено |
| Отсутствие данных в запросе | Null | Null |
Отдельно стоят два «особых» значения:
- 🔹
Неопределено— значение не присвоено. Его возвращают, например,Массив.Найти()иТаблицаЗначений.Найти(), если ничего не нашли. А вотНайтиПоКоду()у менеджера справочника вернёт неНеопределено, а пустую ссылку. Это же пустое значение реквизита составного типа. - 🔸
Null— отсутствие значения в базе данных. Чаще всего приходит из запроса: левое соединение не нашло пары, или вы обратились через точку к реквизиту пустой ссылки.
Null и Неопределено — разные значения. Выражение Null = Неопределено даёт Ложь, поэтому проверка «на Неопределено» пропустит Null из запроса.
Пять способов проверить значение на пустоту во встроенном языке
1. ЗначениеЗаполнено() — универсальный способ
Функция работает с любым типом и доступна и на сервере, и на клиенте. Это основной инструмент: в 9 случаях из 10 достаточно его.
Если Не ЗначениеЗаполнено(Объект.Контрагент) Тогда
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Не указан контрагент";
Сообщение.Поле = "Объект.Контрагент";
Сообщение.Сообщить();
Возврат;
КонецЕсли;
Одна функция заменяет цепочку сравнений Значение = Неопределено ИЛИ Значение = Null ИЛИ Значение.Пустая(). Для составного реквизита она тоже корректна: и Неопределено, и пустая ссылка любого из типов дадут Ложь.
Для чисел ноль — это «не заполнено». Если в поле «Скидка, %» ноль — законное значение, ЗначениеЗаполнено() здесь не подходит. Проверяйте то, что действительно запрещено, например Скидка < 0.
2. Метод Пустая() у ссылки
У любой ссылки (справочник, документ, перечисление, план видов характеристик) есть метод Пустая().
Если Объект.Организация.Пустая() Тогда
// организация не выбрана
КонецЕсли;
Метод удобен, когда тип точно известен. Но если в переменной окажется Неопределено или Null, получите ошибку Метод объекта не обнаружен (Пустая). Для реквизитов составного типа и данных из запроса берите ЗначениеЗаполнено().
3. Сравнение с пустым значением типа
Прямое сравнение читается однозначно и не зависит от особенностей функции:
Если Объект.ДатаОплаты = Дата(1, 1, 1) Тогда
// дата не указана
КонецЕсли;
Если Склад = Справочники.Склады.ПустаяСсылка() Тогда
// склад не выбран
КонецЕсли;
На клиенте менеджеры справочников недоступны. Там пустую ссылку получают так: ПредопределенноеЗначение("Справочник.Склады.ПустаяСсылка").
4. ПустаяСтрока() — для текста с пробелами
Строка " " формально непустая: у неё длина 3. Пользователь видит пустое поле, а Строка = "" вернёт Ложь. Глобальная функция ПустаяСтрока() проверяет, есть ли в строке значащие символы, и пробелы с переносами не считает.
Если ПустаяСтрока(Объект.Комментарий) Тогда
// текста нет, даже если пользователь набил пробелов
КонецЕсли;
Аналог без отдельной функции — СокрЛП(Строка) = "".
5. Проверка типа: ТипЗнач()
Когда важно отличить Null от Неопределено или от пустой ссылки, сравнивайте тип:
Если ТипЗнач(Значение) = Тип("Null") Тогда
// данных в базе нет — например, левое соединение не нашло строку
ИначеЕсли Значение = Неопределено Тогда
// значение не присвоено
ИначеЕсли Не ЗначениеЗаполнено(Значение) Тогда
// пустое значение своего типа: 0, "", пустая дата или ссылка
КонецЕсли;
| Способ | Когда применять | Чем рискуете |
|---|---|---|
ЗначениеЗаполнено() | почти всегда | ноль у числа считается пустым |
.Пустая() | тип точно ссылочный | ошибка на Неопределено и Null |
= ПустаяСсылка() / Дата(1,1,1) | нужен конкретный тип | на клиенте нет менеджеров |
ПустаяСтрока() | строки из ручного ввода, файлов | только для строк |
ТипЗнач() | надо различить Null и Неопределено | громоздко |
Как проверить на пустое значение в запросе 1С
Язык запросов живёт по своим правилам. Функции ЗначениеЗаполнено() в нём нет, а Null ведёт себя как в SQL: любое сравнение с ним не даёт истины.
ЕСТЬ NULL и функция ЕСТЬNULL()
Чтобы отобрать строки, для которых в присоединённой таблице ничего не нашлось, пишут ЕСТЬ NULL. Запись Поле = NULL не работает
.
ВЫБРАТЬ
Номенклатура.Ссылка КАК Товар,
ЕСТЬNULL(Остатки.КоличествоОстаток, 0) КАК Остаток
ИЗ
Справочник.Номенклатура КАК Номенклатура
ЛЕВОЕ СОЕДИНЕНИЕ РегистрНакопления.ТоварыНаСкладах.Остатки КАК Остатки
ПО Номенклатура.Ссылка = Остатки.Номенклатура
ГДЕ
Остатки.Номенклатура ЕСТЬ NULL
Запрос вернёт товары без остатков, а ЕСТЬNULL(..., 0) подставит ноль вместо Null. Без этой подстановки сложение Остаток + Приход в запросе даст Null, а в коде попытка сложить Null с числом упадёт с ошибкой преобразования типа.
Регистр накопления в примере условный. Подставьте свой: имена регистров в типовых конфигурациях разные.
Пустые ссылки, даты и строки в условиях
Пустая ссылка в тексте запроса задаётся через ЗНАЧЕНИЕ():
ГДЕ
Документ.Контрагент = ЗНАЧЕНИЕ(Справочник.Контрагенты.ПустаяСсылка)
ИЛИ Документ.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
ИЛИ Документ.НомерВходящий = ""
Тот же результат через параметр — если пустое значение приходит из кода:
Запрос.УстановитьПараметр("ПустойКонтрагент", Справочники.Контрагенты.ПустаяСсылка());
Для реквизита составного типа одной проверки на пустую ссылку мало: пустым он может быть как Неопределено. Надёжное условие — Поле = НЕОПРЕДЕЛЕНО ИЛИ Поле ЕСТЬ NULL плюс сравнение с пустыми ссылками тех типов, что в него входят.
Строки неограниченной длины
Реквизит типа «Строка» без ограничения длины нельзя сравнивать в запросе напрямую — платформа выдаст ошибку о недопустимом сравнении. Обрежьте значение до фиксированной длины:
ГДЕ
ПОДСТРОКА(Документ.Комментарий, 1, 1) = ""
Или приведите тип: ВЫРАЗИТЬ(Документ.Комментарий КАК СТРОКА(10)) = "". Если таких проверок много, имеет смысл задать реквизиту длину в конфигураторе.
Пустые и «битые» ссылки: в чём разница
Пустая ссылка ни на что не указывает. «Битая» ссылка хранит идентификатор объекта, которого в базе больше нет: его удалили напрямую, минуя контроль ссылочной целостности, или данные пришли из обмена без самого объекта. На форме такая ссылка выглядит как <Объект не найден> (...).
Ни ЗначениеЗаполнено(), ни Пустая() битую ссылку не поймают: идентификатор у неё есть, значит, она «заполнена». Проверить, существует ли объект, можно тремя путями:
- В конфигурациях на БСП (БП 3.0, ЗУП 3.1, УТ 11) — функцией
ОбщегоНазначения.СсылкаСуществует(Ссылка)на сервере. - Методом
ПолучитьОбъект(): для несуществующего объекта он вернётНеопределено. Способ тяжёлый — читает объект целиком, в циклах его не используйте. - Запросом к таблице объекта:
Запрос = Новый Запрос(
"ВЫБРАТЬ ПЕРВЫЕ 1
| ИСТИНА
|ИЗ
| Справочник.Контрагенты КАК Т
|ГДЕ
| Т.Ссылка = &Ссылка");
Запрос.УстановитьПараметр("Ссылка", Ссылка);
ОбъектЕсть = Не Запрос.Выполнить().Пустой();
Метод Пустой() у результата запроса — тоже проверка на пустоту, только для выборки: он отвечает, вернул ли запрос хоть одну строку. Это быстрее, чем выгружать результат в таблицу и считать строки.
Приёмы для составных типов, структур и коллекций
Свойство структуры может отсутствовать
Обращение Параметры.Организация к структуре, где ключа нет, вызывает ошибку. Безопасный вариант — метод Свойство() со вторым параметром:
Организация = Неопределено;
Если Не Параметры.Свойство("Организация", Организация)
Или Не ЗначениеЗаполнено(Организация) Тогда
Организация = ЗначениеПоУмолчанию; // ваша логика
КонецЕсли;
Одна строка закрывает оба случая: ключа нет и ключ есть, но значение пустое.
Пустая табличная часть и коллекция
Для таблиц, массивов и списков значений проверяйте количество элементов — так условие однозначно для любого читателя кода:
Если Объект.Товары.Количество() = 0 Тогда
// табличная часть пуста
КонецЕсли;
Найти незаполненные строки табличной части удобнее циклом с ЗначениеЗаполнено() по нужной колонке. Номер строки берите из Строка.НомерСтроки, а не считайте сами.
Пустой результат с точкой через реквизит
Объект.Договор.Владелец при пустом договоре во встроенном языке вернёт пустое значение типа реквизита, а в запросе — Null. Код, который одинаково обрабатывает данные из объекта и из запроса, должен учитывать оба варианта. Здесь снова выручает ЗначениеЗаполнено(): ей всё равно, что пришло.
Проверка пустых значений на управляемой форме
На форме проверка заполнения бывает трёх видов, и их лучше не смешивать.
Декларативная. В конфигураторе у реквизита объекта есть свойство «Проверка заполнения» со значением «Выдавать ошибку». Платформа сама не даст провести или записать объект с пустым реквизитом и подсветит поле. Писать код не нужно.
Программная — в модуле объекта. Условные проверки («КПП обязателен только для юрлиц») пишут в обработчике ОбработкаПроверкиЗаполнения. Он получает массив ПроверяемыеРеквизиты, из которого можно убрать лишнее:
Процедура ОбработкаПроверкиЗаполнения(Отказ, ПроверяемыеРеквизиты)
Если ВидКонтрагента <> Перечисления.ВидыКонтрагентов.ЮридическоеЛицо Тогда
Индекс = ПроверяемыеРеквизиты.Найти("КПП");
Если Индекс <> Неопределено Тогда
ПроверяемыеРеквизиты.Удалить(Индекс);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Перечисление ВидыКонтрагентов здесь условное: в типовой конфигурации вид контрагента может храниться иначе. Смысл приёма — отключать проверку по условию, а не дублировать её вручную.
Визуальная — подсветка поля. У поля формы есть свойства АвтоОтметкаНезаполненного и ОтметкаНезаполненного. Первое включает красное подчёркивание пустого поля автоматически, второе позволяет управлять им из кода. Отметка ничего не запрещает — это только подсказка пользователю.
Пустые значения без программирования
Пользователю код не нужен. В отборе любого списка и в настройках отчёта на СКД есть виды сравнения «Заполнено» и «Не заполнено». Откройте настройки списка через меню Ещё, на закладке отбора добавьте поле и выберите «Не заполнено» — список покажет, например, все документы без указанного договора.
Ошибки, на которых чаще всего спотыкаются
- ❌
Метод объекта не обнаружен (Пустая). В переменнойНеопределеноилиNull, а не ссылка. Замените.Пустая()наЗначениеЗаполнено(). - ❌ Условие
Поле = NULLв запросе ничего не отбирает. ПишитеПоле ЕСТЬ NULLилиНЕ Поле ЕСТЬ NULL. - ❌ Документ с нулевой суммой не проходит проверку. Для числа ноль — пустое значение. Если ноль допустим,
ЗначениеЗаполнено()по этому полю не используйте. - ❌ Проверка
= Неопределенопропускает данные из запроса. Из запроса пришёлNull. ИспользуйтеЗначениеЗаполнено()илиЕСТЬNULL()прямо в тексте запроса. - ❌
Справочники.Склады.ПустаяСсылка()в клиентской процедуре. На клиенте менеджеров нет — используйтеПредопределенноеЗначение()или передайте проверку на сервер. - ❌ Ссылка «заполнена», а объекта нет. Это битая ссылка; ищите её через
СсылкаСуществует()или запрос, а не черезЗначениеЗаполнено().
Частые вопросы
Чем ЗначениеЗаполнено() отличается от проверки на Неопределено?
ЗначениеЗаполнено() считает пустыми и Неопределено, и Null, и пустые значения конкретных типов: 0, пустую строку, пустую дату и ссылку. Сравнение = Неопределено ловит только одно из них.Можно ли использовать ЗначениеЗаполнено() в запросе?
ЕСТЬ NULL, ЕСТЬNULL() и сравнение с ЗНАЧЕНИЕ(...ПустаяСсылка), пустой датой или пустой строкой.Как проверить, что запрос ничего не вернул?
Пустой() у результата: Если Запрос.Выполнить().Пустой() Тогда. Выгружать результат и считать строки для этого не нужно.Работает ли ЗначениеЗаполнено() на клиенте?
ПредопределенноеЗначение().Как найти все документы с незаполненным реквизитом без кода?
Ещё откройте настройки списка и добавьте отбор по реквизиту с видом сравнения «Не заполнено».