Как в запросе 1С сделать отбор по пустой дате с помощью логического параметра?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В процессе разработки отчетов и алгоритмов обработки данных часто возникает задача опциональной фильтрации: если пользователь взводит флаг (булево значение Истина), запрос должен отбирать только строки с незаполненной датой, а если флаг снят (Ложь) — возвращать все строки без ограничений по дате. Разберем по шагам, как правильно задать пустую дату в языке запросов 1С, как составить логическое условие и какие варианты реализации являются наиболее производительными для СУБД.

Проанализируем специфику типа данных Дата в платформе 1С:Предприятие. Пустое значение даты в 1С соответствует значению 01.01.0001 00:00:00. В тексте запроса литерал пустой даты объявляется с помощью конструкции ДАТАВРЕМЯ(1, 1, 1) или ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0). Кроме того, если дата получается в результате левого соединения таблиц или из реквизита составного типа, незаполненное поле может содержать значение NULL, что также необходимо учитывать при построении условий.

Вариант 1. Использование логического выражения с оператором ИЛИ в секции ГДЕ

Рассмотрим наиболее простой способ, позволяющий передавать логический параметр типа Булево прямо в запрос без изменения текста самого запроса. Логика работы следующая: если параметр равен Ложь (флаг выключен), выражение НЕ &ТолькоПустые возвращает Истина, и условие выполняется для всех строк. Если параметр равен Истина, первая часть выражения становится ложной, и запрос проверяет равенство даты пустой величине.

Посмотрим на пример текста запроса:


ВЫБРАТЬ
    Таблица.Ссылка КАК Документ,
    Таблица.Дата КАК ДатаДокумента
ИЗ
    Документ.ПоступлениеТоваровУслуг КАК Таблица
ГДЕ
    НЕ &ТолькоПустые ИЛИ Таблица.Дата = ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0)

Если в выборке могут присутствовать строки со значением NULL (например, при обращении к реквизитам через точку или при использовании левого соединения), обязательно защитим запрос от некорректного сравнения:


ВЫБРАТЬ
    Заказ.Ссылка КАК Заказ,
    Реализация.Дата КАК ДатаОтгрузки
ИЗ
    Документ.ЗаказКлиента КАК Заказ
    ЛЕВОЕ СОЕДИНЕНИЕ Документ.РеализацияТоваровУслуг КАК Реализация
        ПО Заказ.Ссылка = Реализация.ЗаказКлиента
ГДЕ
    НЕ &ТолькоПустые 
    ИЛИ ЕСТЬNULL(Реализация.Дата, ДАТАВРЕМЯ(1, 1, 1)) = ДАТАВРЕМЯ(1, 1, 1)

В коде на встроенном языке передача параметра выглядит стандартно:


Запрос = Новый Запрос;
Запрос.Текст = "..."; // Текст запроса
Запрос.УстановитьПараметр("ТолькоПустые", ФлагТолькоПустые);
Результат = Запрос.Выполнить();

Вариант 2. Конструкция ВЫБОР КОГДА в условии ГДЕ

Разберем альтернативную синтаксическую запись условия через оператор ВЫБОР. Этот подход делает логику ветвления явной:


ВЫБРАТЬ
    Таблица.Ссылка КАК Ссылка,
    Таблица.Дата КАК Дата
ИЗ
    Документ.ПоступлениеТоваровУслуг КАК Таблица
ГДЕ
    ВЫБОР
        КОГДА &ТолькоПустые ТОГДА Таблица.Дата = ДАТАВРЕМЯ(1, 1, 1)
        ИНАЧЕ ИСТИНА
    КОНЕЦ

Важно: Обратите внимание на типичную ошибку начинающих разработчиков: попытку в ветке ИНАЧЕ возвращать само поле (например, ИНАЧЕ Таблица.Дата). Секция ГДЕ ожидает только логическое выражение (возвращающее ИСТИНА или ЛОЖЬ), поэтому возвращать значение поля даты туда нельзя.

Вариант 3. Динамическое формирование текста запроса (рекомендуемый для оптимизации)

Проанализируем производительность. Конструкции вида ГДЕ НЕ &Параметр ИЛИ Поле = Значение или операторы ВЫБОР в секции ГДЕ могут приводить к деградации плана выполнения в СУБД (MS SQL Server, PostgreSQL). СУБД не может заранее определить, будет ли использоваться индекс по дате, и выполняет полное сканирование таблицы (Table Scan) вместо эффективного поиска по индексу (Index Seek).

Чтобы избежать падения производительности на больших объемах данных, сформируем текст запроса динамически на встроенном языке:


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

ТекстЗапроса = 
"ВЫБРАТЬ
|   Таблица.Ссылка КАК Документ,
|   Таблица.Дата КАК ДатаДокумента
|ИЗ
|   Документ.ПоступлениеТоваровУслуг КАК Таблица";

Если ТолькоПустыеДаты Тогда
    ТекстЗапроса = ТекстЗапроса + "
    |ГДЕ
    |   Таблица.Дата = ДАТАВРЕМЯ(1, 1, 1)";
КонецЕсли;

Запрос.Текст = ТекстЗапроса;
Результат = Запрос.Выполнить();

При таком подходе СУБД получает идеально оптимизированный запрос: если флаг не установлен, фильтрация отсутствует вовсе; если установлен — используется индекс по полю даты без лишних логических ветвлений.

Вариант 4. Программное управление условиями через объект СхемаЗапроса

Если необходимо избежать прямого склеивания строк в коде и работать с запросом как с объектной моделью, воспользуемся встроенным объектом СхемаЗапроса:

  1. Инициализируем объект СхемаЗапроса и загружаем исходный текст без условий.
  2. Получаем коллекцию условий нужного оператора Выбрать.
  3. Если флаг взведен, программно добавляем условие в коллекцию Условия.
  4. Получаем готовый оптимизированный текст с помощью метода ПолучитьТекст().

Посмотрим на пример реализации:


Схема = Новый СхемаЗапроса;
Схема.УстановитьТекстЗапроса(
"ВЫБРАТЬ
|   Таблица.Ссылка КАК Документ,
|   Таблица.Дата КАК ДатаДокумента
|ИЗ
|   Документ.ПоступлениеТоваровУслуг КАК Таблица");

ОператорВыбрать = Схема.ПакетЗапросов[0].Операторы[0];

Если ТолькоПустыеДаты Тогда
    ОператорВыбрать.Условия.Добавить("Таблица.Дата = ДАТАВРЕМЯ(1, 1, 1)");
КонецЕсли;

Запрос = Новый Запрос;
Запрос.Текст = Схема.ПолучитьТекст();
Выборка = Запрос.Выполнить().Выбрать();

Вариант 5. Использование в Системе компоновки данных (СКД)

Если разработка ведется в отчете на СКД, писать сложные логические условия в тексте запроса не требуется. Рассмотрим два стандартных механизма СКД:

  1. Необязательные условия в фигурных скобках: В тексте запроса СКД указываем секцию расширения языка запросов:
    
    ВЫБРАТЬ
        Таблица.Ссылка КАК Документ,
        Таблица.Дата КАК ДатаДокумента
    ИЗ
        Документ.ПоступлениеТоваровУслуг КАК Таблица
    {ГДЕ
        Таблица.Дата = ДАТАВРЕМЯ(1, 1, 1)}
    
    Компоновщик сам добавит это условие в итоговый SQL-запрос только тогда, когда пользователь включит соответствующий отбор в настройках.
  2. Стандартный вид сравнения СКД: В настройках отбора на вкладке «Отбор» выбираем поле Дата и устанавливаем вид сравнения Не заполнено. Механизм компоновки автоматически сформирует корректный отбор как для пустой даты 0001-01-01, так и для значений NULL.
← На главную