Как преобразовать число в дату в запросе и параметрах СКД?

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

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

Способ 1: Математическое преобразование в тексте запроса

Рассмотрим ситуацию, когда у нас уже есть параметр &Год (тип Число), и нам нужно получить из него дату прямо в теле запроса. Основная сложность заключается в том, что стандартная функция ДАТАВРЕМЯ в языке запросов 1С принимает в качестве аргументов только константы. Мы не можем написать ДАТАВРЕМЯ(&Год, 1, 1) — это вызовет ошибку синтаксиса.

Для решения этой задачи проанализируем функцию ДОБАВИТЬКДАТЕ. Она позволяет прибавлять к уже существующей дате определенное количество временных интервалов (год, месяц, день). Мы можем взять «нулевую» дату платформы (01.01.0001) и прибавить к ней нужное количество лет.

Разберем по шагам логику вычисления:

  1. За основу берем константу ДАТАВРЕМЯ(1, 1, 1).
  2. Добавляем к ней значение нашего параметра.
  3. Учитываем смещение: так как мы начинаем с первого года, при вводе «2023» нам нужно прибавить 2022 года, чтобы получить 01.01.2023.

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


ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), ГОД, &Год - 1) КАК НачалоГода,
    ДОБАВИТЬКДАТЕ(ДОБАВИТЬКДАТЕ(ДАТАВРЕМЯ(1, 1, 1), ГОД, &Год), ДЕНЬ, -1) КАК КонецГода

Этот метод универсален и работает непосредственно на стороне СУБД, что полезно, если вы не хотите полагаться на механизмы предварительной обработки параметров СКД.

Способ 2: Использование выражений в параметрах СКД

Система компоновки данных предоставляет более элегантный механизм — закладку «Параметры». Здесь мы можем разделить параметр, который видит пользователь, и параметр, который используется в запросе.

Рассмотрим алгоритм настройки:

  1. Создаем параметр ГодЧислом (тип Число, длина 4). Именно его мы выводим в пользовательские настройки.
  2. Создаем второй параметр ПериодОтчета (тип Дата). В колонке «Ограничение доступности» ставим галочку, чтобы пользователь его не видел.
  3. В колонке «Выражение» для параметра ПериодОтчета пишем код на языке выражений СКД.

В языке выражений СКД, в отличие от языка запросов, доступна функция Дата(), аналогичная встроенному языку 1С. Пропишем следующее выражение:

Дата(&ГодЧислом, 1, 1)

Теперь в основном запросе вы можете смело использовать ГДЕ ПолеДата >= &ПериодОтчета. Платформа сама вычислит дату перед выполнением запроса.

Способ 3: Настройка формата редактирования (UX-подход)

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

Выясним, как это сделать:

  1. Перейдем на закладку «Параметры» в СКД.
  2. Выберем параметр типа Дата.
  3. В колонке «Параметры редактирования» найдем свойство «Формат редактирования».
  4. Установим строку формата: ДФ=yyyy.

В этом случае пользователь увидит в поле ввода только четыре цифры года. При выборе значения 1С автоматически подставит дату на начало этого года (01.01.ГГГГ 00:00:00). Это избавляет нас от необходимости писать какой-либо код для преобразования типов.

Способ 4: Обработка в модуле (ПриКомпоновкеРезультата)

Если логика отчета требует сложной предварительной подготовки (например, год должен преобразовываться в финансовый период, зависящий от настроек учетной политики), лучше всего использовать процедуру ПриКомпоновкеРезультата в модуле объекта отчета.

Посмотрим на пример кода, который перехватывает управление:


Процедура ПриКомпоновкеРезультата(ДанныеРасшифровки, СтандартнаяОбработка)
    
    СтандартнаяОбработка = Ложь;
    
    // Получаем настройки пользователя
    Настройки = КомпоновщикНастроек.ПолучитьНастройки();
    
    // Ищем наш числовой параметр
    ПараметрГод = Настройки.ПараметрыДанных.Элементы.Найти("Год");
    Если ПараметрГод <> Неопределено Тогда
        ГодЗначение = ПараметрГод.Значение;
        // Преобразуем число в дату
        ДатаНачала = Дата(ГодЗначение, 1, 1);
        
        // Устанавливаем скрытый параметр для запроса
        Настройки.ПараметрыДанных.УстановитьЗначениеПараметра("НачалоПериода", ДатаНачала);
    КонецЕсли;
    
    // Выполняем компоновку
    КомпоновщикМакета = Новый КомпоновщикМакетаКомпоновкиДанных;
    МакетКомпоновки = КомпоновщикМакета.Выполнить(СхемаКомпоновкиДанных, Настройки, ДанныеРасшифровки);
    
    ПроцессорКомпоновки = Новый ПроцессорКомпоновкиДанных;
    ПроцессорКомпоновки.Инициализировать(МакетКомпоновки, , ДанныеРасшифровки);
    
    ПроцессорВывода = Новый ПроцессорВыводаРезультатаКомпоновкиДанныхВТабличныйДокумент;
    ПроцессорВывода.УстановитьДокумент(Результат);
    ПроцессорВывода.Вывести(ПроцессорКомпоновки);
    
КонецПроцедуры

Проблема производительности: Запросы vs Отборы

Проанализируем ситуацию, затронутую в обсуждении: где эффективнее выполнять условия — в виртуальных таблицах или через ГДЕ? При использовании преобразований типов в запросе важно помнить о SARGability (способности СУБД использовать индексы).

Важные правила:

  1. Не преобразуйте поля таблиц: Выражение ГОД(Таблица.Дата) = &ВыбранныйГод заставит SQL-сервер сканировать всю таблицу (Index Scan или Table Scan), так как он не может использовать индекс по полю Дата.
  2. Преобразуйте параметры: Всегда старайтесь привести параметр &Год к границам дат (Начало и Конец года) заранее. Выражение Таблица.Дата МЕЖДУ &НачалоГода И &КонецГода отработает мгновенно, используя индекс.

Именно поэтому Способ 2 (Выражение в параметрах СКД) является наиболее предпочтительным: он сохраняет «чистоту» и производительность SQL-запроса, обеспечивая при этом удобство ввода для пользователя.

Использование внешних функций

Если ваше решение подразумевает сложную логику, которую трудно описать одной строкой, вспомните о возможности вызова функций общих модулей в выражениях СКД. Например:

МойОбщийМодуль.ПолучитьНачалоПериода(&ГодЧислом)

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

← На главную