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