Как правильно рассчитать разность дат в запросе 1С и СКД при пустой дате или значении NULL?

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

При построении отчетов по взаиморасчетам или отгрузкам нередко возникает задача вычислить количество дней между двумя событиями — например, между плановой датой поступления и фактической датой оплаты. Однако если оплата еще не производилась, поле даты регистратора оказывается незаполненным. В таких ситуациях прямое использование функции РАЗНОСТЬДАТ приводит либо к получению значения NULL, либо к неверным отрицательным величинам.

Разберем детально, почему попытка сравнения Дата = 0 вызывает ошибку, как платформа 1С обрабатывает пустые значения и как правильно составить выражение для запроса и схемы компоновки данных (СКД).

Причины возникновения ошибок и некорректных расчетов

Проанализируем основные факторы, из-за которых расчет количества дней может давать неверный результат:

  1. Особенности работы функции с пустыми значениями: Если хотя бы один из параметров функции РАЗНОСТЬДАТ содержит NULL, вся функция возвращает NULL. В языке запросов 1С при левом соединении с таблицей движений отсутствие записи возвращает именно NULL, а не число 0. Условие вида Дата = 0 является синтаксически неверным, так как поле имеет тип Дата, а не числовой.
  2. Представление пустой даты: В платформе 1С пустая дата задается литералом ДАТАВРЕМЯ(1, 1, 1, 0, 0, 0). Поэтому при проверке реквизитов документов необходимо учитывать как возможное значение NULL (запись отсутствует в выборке), так и незаполненную дату.
  3. Порядок параметров в функции: Функция платформы имеет следующий синтаксис: РАЗНОСТЬДАТ(НачальнаяДата, КонечнаяДата, Периодичность). Результат вычисляется как КонечнаяДата минус НачальнаяДата. Если передать параметры в неверном порядке (например, передать текущую дату первой, а прошедшую плановую дату второй), функция вернет отрицательное число дней.
  4. Обращение через точку к составному типу: Поле Регистратор в таблицах регистров бухгалтерии и накопления имеет составной тип. Конструкция Регистратор.Дата порождает неявные соединения со всеми таблицами документов, входящих в тип регистратора, что замедляет выполнение запроса. Оптимальнее использовать стандартное поле регистра Период.

Решение 1. Обработка условия в тексте запроса с помощью ВЫБОР

Рассмотрим проверенный способ вычисления разности дней непосредственно в тексте запроса. Чтобы отчет работал корректно как при наличии даты, так и при ее отсутствии, используем конструкцию ВЫБОР с проверкой на NULL и пустую дату:


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

Если в базе данных гарантированно не бывает записанных пустых дат, а отсутствие движения всегда дает NULL в результате левого соединения, код можно сократить с помощью функции ЕСТЬNULL:


РАЗНОСТЬДАТ(
    ЕСТЬNULL(ХозрасчетныйДвиженияССубконто.Период, &ТекущаяДата),
    Отгрузка.ПланируемаяДатаПоступления,
    ДЕНЬ
)

Решение 2. Настройка параметра текущей даты в СКД

Если отчет разрабатывается в Системе компоновки данных (СКД), разработчику нет необходимости программно передавать параметр текущей даты через Запрос.УстановитьПараметр. Настроим автозаполнение даты средствами схемы:

  1. Откроем схему компоновки данных и перейдем на вкладку Параметры.
  2. Найдем параметр &ТекущаяДата, который используется в запросе.
  3. В колонке Выражение пропишем стандартную функцию СКД: ТекущаяДата() или НачалоПериода(ТекущаяДата(), "День"), чтобы обнулить время и избежать погрешности при подсчете целых дней.
  4. Установим флажок Ограничение доступности, чтобы скрыть этот параметр от пользователя в пользовательских настройках отчета.

Решение 3. Перенос вычислений в «Вычисляемые поля» СКД

Посмотрим на альтернативный вариант решения, когда запрос остается простым, а логика расчета дней переносится на уровень компоновщика данных. Это избавляет от необходимости добавлять вспомогательные параметры в текст запроса.

Перейдем на вкладку Вычисляемые поля схемы компоновки данных, добавим новое поле (например, ПросрочкаДней) и в колонке Выражение укажем формулу на языке выражений СКД:


РазностьДат(
    Выбор
        Когда ХозрасчетныйДвиженияССубконтоПериод Есть Null
            Или ХозрасчетныйДвиженияССубконтоПериод = ДатаВремя(1, 1, 1, 0, 0, 0)
            Тогда ТекущаяДата()
        Иначе ХозрасчетныйДвиженияССубконтоПериод
    Конец,
    ОтгрузкаПланируемаяДатаПоступления,
    "День"
)

Обратите внимание на синтаксис языка СКД: в отличие от языка запросов, в вычисляемых полях функция ТекущаяДата() вызывается напрямую, а периодичность (третий параметр) указывается строковым литералом в кавычках — "День".

← На главную