Как в запросе 1С выбрать дату по условию и установить на нее отбор

Программист 1С v8.3 (Управляемые формы) Бухгалтерский учет
← На главную

При разработке отчетов и обработок в системе 1С часто возникает ситуация, когда логика выбора данных зависит от заполненности тех или иных полей. Одной из классических задач является выбор «актуальной» даты: например, если заполнена специальная дата (дата корректировки или разделения), мы должны использовать её, а если нет — стандартную дату документа или ввода. В этой статье мы подробно разберем, как реализовать такую проверку в запросе и, что более важно, как правильно наложить фильтр на полученный результат.

Реализация выбора даты через конструкцию ВЫБОР

Для начала разберем базовую задачу: как в списке выбора ВЫБРАТЬ указать условие. В языке запросов 1С для этого используется оператор ВЫБОР. Важно помнить, что «пустая» дата в 1С — это не NULL (хотя NULL тоже может возникнуть при соединениях), а специальное значение ДАТАВРЕМЯ(1, 1, 1).

Рассмотрим пример, где нам нужно выбрать дату. Если поле ДатаРазделения заполнено, берем его, иначе — ДатаВвода. Напишем конструкцию:


ВЫБОР
    КОГДА СправочникОС.ДатаРазделения = ДАТАВРЕМЯ(1, 1, 1)
        ТОГДА СправочникОС.ДатаВвода
    ИНАЧЕ СправочникОС.ДатаРазделения
КОНЕЦ КАК ВыбДата

В этом коде мы проверяем ДатаРазделения на равенство пустой дате. Если условие истинно, система возвращает значение из второго поля. Обратите внимание на использование псевдонима КАК ВыбДата — он пригодится нам для отображения результата в отчете.

Проблема использования псевдонима в секции ГДЕ

Часто программисты пытаются использовать созданный псевдоним ВыбДата прямо в условии фильтрации, например: ГДЕ ВыбДата МЕЖДУ &ДатаНач И &ДатаКон. Однако при попытке выполнить такой запрос система выдаст ошибку: «Поле не найдено "ВыбДата"».

Выясним причину этой ошибки. Согласно логике исполнения SQL-запроса (на котором базируется язык запросов 1С), секция ГДЕ обрабатывается базой данных раньше, чем формируются поля в секции ВЫБРАТЬ. На момент наложения фильтра система еще ничего не знает о существовании «поля» ВыбДата.

Проанализируем два основных способа решения этой проблемы:

  1. Дублирование условия: Повторение всей конструкции ВЫБОР непосредственно в секции ГДЕ.
  2. Использование вложенных запросов или временных таблиц: Вычисление даты на первом этапе и фильтрация на втором.

Вариант 1: Повторение конструкции в условии ГДЕ

Это самый быстрый способ, если запрос небольшой. Мы просто копируем логику выбора в параметры фильтрации МЕЖДУ. Рассмотрим, как это выглядит на практике:


ГДЕ
    ВЫБОР
        КОГДА СправочникОС.ДатаРазделения = ДАТАВРЕМЯ(1, 1, 1)
            ТОГДА СправочникОС.ДатаВвода
        ИНАЧЕ СправочникОС.ДатаРазделения
    КОНЕЦ МЕЖДУ &ДатаНач И &ДатаКон

Несмотря на кажущуюся избыточность, этот метод отлично работает. Однако у него есть существенный минус — производительность. Когда мы используем ВЫБОР внутри ГДЕ, СУБД часто не может использовать индексы по полям дат (это называется «non-SARGable» условие), что может привести к замедлению работы на больших таблицах.

Вариант 2: Использование временных таблиц (Рекомендуемый подход)

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

Шаг 1. Создаем временную таблицу, в которой вычисляем нужную дату:


ВЫБРАТЬ
    ОС.Ссылка КАК Ссылка,
    ВЫБОР
        КОГДА ОС.ДатаРазделения = ДАТАВРЕМЯ(1, 1, 1)
            ТОГДА ОС.ДатаВвода
        ИНАЧЕ ОС.ДатаРазделения
    КОНЕЦ КАК АктуальнаяДата
ПОМЕСТИТЬ ВТ_ДанныеОС
ИЗ
    Справочник.ОсновныеСредства КАК ОС
;

Шаг 2. Выбираем данные из временной таблицы, где поле АктуальнаяДата уже существует и по нему можно легко фильтровать:


ВЫБРАТЬ
    ВТ.Ссылка,
    ВТ.АктуальнаяДата
ИЗ
    ВТ_ДанныеОС КАК ВТ
ГДЕ
    ВТ.АктуальнаяДата МЕЖДУ &ДатаНач И &ДатаКон

Типизация полей и работа с составными типами

В сложных запросах, например, при работе с регистром бухгалтерии, поле Субконто имеет составной тип. Если мы обращаемся к реквизиту через точку (например, Субконто1.ДатаРазделения), система выполняет неявное соединение со всеми таблицами, входящими в этот тип. Это может катастрофически снизить скорость выполнения.

Посмотрим на пример правильной типизации с помощью функции ВЫРАЗИТЬ. Это «подсказывает» системе, к какой именно таблице нужно обращаться:


ВЫБОР
    КОГДА ВЫРАЗИТЬ(УправленческийОстатки.Субконто1 КАК Справочник.ОсновныеСредства).ДатаРазделения = ДАТАВРЕМЯ(1, 1, 1)
        ТОГДА ВЫРАЗИТЬ(УправленческийОстатки.Субконто1 КАК Справочник.ОсновныеСредства).ДатаВвода
    ИНАЧЕ ВЫРАЗИТЬ(УправленческийОстатки.Субконто1 КАК Справочник.ОсновныеСредства).ДатаРазделения
КОНЕЦ

Использование ВЫРАЗИТЬ гарантирует, что запрос не будет пытаться искать поле ДатаРазделения в справочниках «Контрагенты» или «Номенклатура», если они также входят в состав Субконто1.

Тонкости работы с NULL

При использовании ЛЕВОЕ СОЕДИНЕНИЕ поле даты может содержать NULL. Помните, что NULL не равен ДАТАВРЕМЯ(1, 1, 1). Если вы ожидаете, что дата может отсутствовать вовсе (запись не найдена в присоединенной таблице), используйте функцию ЕСТЬNULL.

Проанализируем пример совмещения проверок:


ВЫБОР
    КОГДА ЕСТЬNULL(ДопСведения.ДатаСобытия, ДАТАВРЕМЯ(1, 1, 1)) = ДАТАВРЕМЯ(1, 1, 1)
        ТОГДА Документ.Дата
    ИНАЧЕ ДопСведения.ДатаСобытия
КОНЕЦ

Подведем итоги: для корректной проверки заполнения даты используйте ВЫБОР с проверкой на ДАТАВРЕМЯ(1, 1, 1). Если результат нужно использовать в фильтре, выносите логику во временную таблицу или дублируйте ВЫБОР в секции ГДЕ. Всегда используйте ВЫРАЗИТЬ для полей составного типа, чтобы ваш код работал быстро и стабильно.

← На главную