Почему в 1С 8.3 не работает вычисление дат в параметрах виртуальной таблицы СрезПоследних и как это исправить?

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

При переводе конфигураций с платформы 1С:Предприятие 8.2 на платформу 8.3 разработчики нередко сталкиваются с ситуацией, когда ранее работавшие запросы начинают вызывать синтаксические ошибки. Типичный пример — попытка вычислить дату среза непосредственно в первом параметре виртуальной таблицы регистра сведений, например, с помощью функций ДОБАВИТЬКДАТЕ и РАЗНОСТЬДАТ.

В этой статье разберем, почему платформа 8.3 выдает ошибку Неверный параметр, какие ограничения накладываются на виртуальные таблицы и как правильно организовать получение среза данных.

Причина возникновения ошибки в платформе 8.3

Рассмотрим фрагмент запроса, который приводил к ошибке:


ВЫБРАТЬ
    СотрудникиОрганизаций.Период,
    СотрудникиОрганизаций.Сотрудник
ИЗ
    РегистрСведений.СотрудникиОрганизаций.СрезПоследних(
        ДОБАВИТЬКДАТЕ(&Дата1, ДЕНЬ, РАЗНОСТЬДАТ(&Дата1, &Дата2, ДЕНЬ) / 2),
    ) КАК СотрудникиОрганизаций

Проанализируем причины, по которым данный код не работает в платформе 8.3:

  1. Ужесточение проверки синтаксиса виртуальных таблиц. В платформе 8.2 внутренний парсер запросов допускал определенные скалярные вычисления в аргументах виртуальных таблиц. В 8.3 анализатор работает строго: в параметры виртуальной таблицы можно передавать только простые параметры запроса (например, &Период) или литералы. Сложные составные выражения с вложенными вызовами функций блокируются на этапе синтаксического контроля.
  2. Требования к типам в функции ДОБАВИТЬКДАТЕ. Третий параметр функции (величина смещения) ожидает строго целочисленное значение. Арифметическая операция деления / 2 в языке запросов всегда возвращает значение с плавающей точкой. Транслятор запроса внутри генератора виртуальной таблицы не выполняет автоматическое неявное приведение к целому числу.
  3. Специфика генерации SQL-кода. Параметры виртуальных таблиц определяют структуру итогового SQL-запроса еще до его отправки в СУБД. Они не могут содержать динамических выражений выборки.

Способ 1. Расчет даты во встроенном языке 1С (рекомендуемый подход)

Выясним наиболее простое и методологически правильное решение. Поскольку исходные параметры &Дата1 и &Дата2 известны заранее и передаются в запрос из встроенного языка, всю арифметику дат следует выполнить до выполнения запроса.

В языке 1С разность двух значений типа Дата возвращает количество секунд. Поэтому расчет середины временного интервала и передача параметра выполняются следующим образом:


// Вычисляем середину периода во встроенном языке
СмещениеВСекундах = (Дата2 - Дата1) / 2;
РасчетныйПериод = Дата1 + СмещениеВСекундах;

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	СотрудникиОрганизаций.Период КАК Период,
    |	СотрудникиОрганизаций.Сотрудник КАК Сотрудник
    |ИЗ
    |	РегистрСведений.СотрудникиОрганизаций.СрезПоследних(&ПериодСреза, ) КАК СотрудникиОрганизаций";

Запрос.УстановитьПараметр("ПериодСреза", РасчетныйПериод);
РезультатЗапроса = Запрос.Выполнить();

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

Способ 2. Вычисление даты в выражении параметра СКД

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

  1. Перейдем на вкладку Параметры схемы компоновки данных.
  2. Для параметра периода среза в колонке Выражение укажем формулу на языке выражений СКД, например: ДобавитьКДате(&Дата1, "Секунда", РазностьДат(&Дата1, &Дата2, "Секунда") / 2).
  3. В тексте запроса в параметре виртуальной таблицы оставим только имя параметра &ПериодСреза.

При формировании отчета СКД сначала вычислит точное скалярное значение, а затем передаст его в виртуальную таблицу.

Способ 3. Построение среза через физическую таблицу (для динамических расчетов)

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


ВЫБРАТЬ
    Регистр.Сотрудник КАК Сотрудник,
    МАКСИМУМ(Регистр.Период) КАК Период
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
    РегистрСведений.СотрудникиОрганизаций КАК Регистр
ГДЕ
    Регистр.Период <= &ЦелеваяДата
СГРУППИРОВАТЬ ПО
    Регистр.Сотрудник
;

ВЫБРАТЬ
    РегистрСрез.Сотрудник КАК Сотрудник,
    РегистрСрез.Период КАК Период,
    РегистрСрез.Организация КАК Организация
ИЗ
    ВТ_МаксимальныеДаты КАК Даты
    ВНУТРЕННЕЕ СОЕДИНЕНИЕ РегистрСведений.СотрудникиОрганизаций КАК РегистрСрез
        ПО Даты.Сотрудник = РегистрСрез.Сотрудник
        И Даты.Период = РегистрСрез.Период

Этот подход гарантирует корректную работу в любых версиях платформы 1С:Предприятие 8.3 при динамических условиях выборки.

← На главную