При разработке отчетов на системе компоновки данных (СКД) программисты часто сталкиваются с ситуацией, когда в наборе данных присутствуют пустые даты (значение 01.01.0001). Если для такого поля в ресурсах просто указать агрегатную функцию Минимум(ДатаПрибытия), результат всегда будет равен пустой дате, если в выборке есть хотя бы одна незаполненная строка. Это происходит потому, что 01.01.0001 — это минимально возможное значение типа Дата в 1С. В данной статье мы подробно разберем, как правильно отсечь пустые значения при расчете итогов, и рассмотрим несколько эффективных способов решения этой задачи.
Прежде чем перейти к конкретным формулам, давайте проанализируем, как работают агрегатные функции в СКД (такие как СУММА, МИНИМУМ, МАКСИМУМ). Важной особенностью системы компоновки данных является то, что агрегатные функции автоматически игнорируют значения NULL. Это фундаментальное свойство мы и будем использовать для решения нашей задачи. Если мы подменим пустую дату на NULL в процессе вычисления ресурса, СКД просто «не заметит» эти строки при поиске минимального значения.
Рассмотрим самый распространенный и быстрый способ. Нам необходимо изменить выражение в колонке «Выражение» на закладке «Ресурсы». Вместо простого обращения к полю, мы напишем логическое условие. Разберем по шагам, как это выглядит:
Для начала используем проверку на соответствие пустой дате через ДАТАВРЕМЯ(1, 1, 1). Выражение будет выглядеть следующим образом:
МИНИМУМ(ВЫБОР
КОГДА ДатаПрибытия = ДАТАВРЕМЯ(1, 1, 1)
ТОГДА NULL
ИНАЧЕ ДатаПрибытия
КОНЕЦ)
Почему это работает? Рассмотрим логику выполнения:
МИНИМУМ возвращает NULL.МИНИМУМ собирает все полученные значения, выбрасывает из них NULL и среди оставшихся реальных дат находит самую раннюю.Этот метод является более современным и наглядным. Проанализируем ситуацию: в СКД выражения ресурсов вычисляются программным процессором компоновки, а это значит, что нам доступны многие функции встроенного языка 1С, которые недоступны в обычных запросах к СУБД. Одной из таких функций является ЗначениеЗаполнено().
Выясним, как упростить наше выражение:
Минимум(Выбор Когда ЗначениеЗаполнено(ДатаПрибытия) Тогда ДатаПрибытия Конец)
Обратите внимание, что в данном примере мы даже не пишем явное ИНАЧЕ NULL. В языке выражений СКД, если условие КОГДА не выполняется и ветка ИНАЧЕ отсутствует, конструкция ВЫБОР по умолчанию возвращает NULL. Это делает код ресурса компактным и легким для чтения. Кроме того, ЗначениеЗаполнено универсальна — если тип поля в будущем изменится, логика проверки на «пустоту» останется корректной.
Иногда логику проверки удобно вынести за пределы ресурсов. Это полезно, если вы планируете использовать «чистую» дату в нескольких местах (например, в разных ресурсах или для вывода в детальных записях). Посмотрим, как это реализовать через Вычисляемые поля:
ДатаПрибытияДляИтогов.ВЫБОР КОГДА ЗначениеЗаполнено(ДатаПрибытия) ТОГДА ДатаПрибытия ИНАЧЕ NULL КОНЕЦ.
Минимум(ДатаПрибытияДляИтогов).
Этот подход позволяет избежать дублирования сложного кода ВЫБОР...КОНЕЦ, если вам нужно посчитать и минимум, и максимум, и среднее значение по одному и тому же правилу фильтрации.
Рассмотрим более сложный сценарий, который упоминался в обсуждении. Существует мощная функция ВычислитьВыражениеСГруппировкойМассив. Она позволяет собрать значения из группировок в массив и применить к ним отбор. Хотя для простой задачи поиска минимума этот метод может быть избыточным (и более медленным), его полезно знать для сложных расчетов.
Синтаксис функции с отбором выглядит так:
Минимум(ВычислитьВыражениеСГруппировкойМассив("ДатаПрибытия", "ДатаПрибытия", "ЗначениеЗаполнено(ДатаПрибытия)"))
Здесь третий параметр — это строка отбора. Система сначала отфильтрует данные по условию ЗначениеЗаполнено(ДатаПрибытия), затем соберет их в массив и только потом вычислит Минимум. Используйте этот метод только в том случае, если вам нужно выполнять агрегацию с учетом контекста других группировок, которые недоступны через обычный ВЫБОР. Для задач нестандартного объединения данных из строк пригодится способ сбора значений колонки из нескольких строк в СКД.
Проанализируем ситуацию: что произойдет, если отчет строится за период, в котором нет ни одной заполненной даты прибытия? В этом случае наше выражение Минимум(ВЫБОР...) вернет NULL. В ячейке отчета это будет выглядеть как пустота. Если при отсутствии данных требуется динамически убрать пустые столбцы, можно использовать прием скрытия колонок без данных в отчетах СКД.
Если бизнес-требования диктуют необходимость выводить в таких случаях какой-то текст или специальное значение, мы можем обернуть нашу функцию в ЕстьNULL. Рассмотрим пример:
ЕстьNULL(Минимум(Выбор Когда ЗначениеЗаполнено(ДатаПрибытия) Тогда ДатаПрибытия Конец), "Данные отсутствуют")
Такой подход делает отчет более профессиональным и понятным для конечного пользователя.
При работе с очень большими объемами данных (сотни тысяч и миллионы строк) вычисления в ресурсах СКД могут нагружать процессор сервера. Если вы заметили замедление формирования отчета, рекомендуется перенести логику замены пустых дат на NULL непосредственно в **Набор данных - запрос**.
В тексте запроса это будет выглядеть так:
ВЫБРАТЬ
ВЫБОР КОГДА Таблица.ДатаПрибытия = ДАТАВРЕМЯ(1, 1, 1) ТОГДА NULL ИНАЧЕ Таблица.ДатаПрибытия КОНЕЦ КАК ДатаПрибытияЧистая
ИЗ
...
В этом случае СКД получит уже «подготовленные» данные, и выполнение агрегатной функции Минимум пройдет максимально быстро на уровне SQL-запроса.
Подведем итог: наиболее рекомендуемым и сбалансированным способом для большинства задач является использование конструкции Минимум(Выбор Когда ЗначениеЗаполнено(Поле) Тогда Поле Конец) непосредственно в настройках ресурсов СКД. Это гибко, наглядно и эффективно.