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