Как исправить ошибку «Ошибка в выражении Момент времени» в консоли запросов 1С и оптимизировать выборку из регистра накопления?

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

При разработке и отладке отчетов в 1С:Предприятии программисты часто используют консоль запросов для быстрой проверки работоспособности запросов к виртуальным таблицам регистров накопления. Однако при работе с параметрами периодов в виртуальной таблице ОстаткиИОбороты можно столкнуться со специфической и на первый взгляд непонятной ошибкой: «Ошибка в выражении Момент времени: , дата...».

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

Выясняем причину: почему возникает ошибка «Ошибка в выражении Момент времени»?

Для начала проанализируем природу типа данных МоментВремени в платформе 1С. Этот тип данных предназначен для точного позиционирования события на временной шкале и физически состоит из двух обязательных полей:

  1. Дата и время (с точностью до секунды).
  2. Ссылка на объект-регистратор (документ, который произвел движение в базе данных).

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

Суть ошибки вида Ошибка в выражении Момент времени: , дата 09.01.2020 0:00:00 заключается в том, что платформа попыталась сформировать объект момента времени, в котором заполнена только дата, а ссылка на документ отсутствует (равна пустому значению или Неопределено). Обратите внимание на запятую в тексте ошибки перед словом «дата» — она как раз указывает на то, что первое поле (ссылка) осталось пустым.

Почему это происходит в консоли запросов? В некоторых версиях консолей (как на обычных, так и на управляемых формах) механизм сериализации параметров работает некорректно. Когда разработчик выбирает тип параметра «МоментВремени» и указывает только дату, консоль не может передать полноценный объект в СУБД. В результате платформа генерирует аварийное завершение запроса.

Решение проблемы с параметрами периода: уходим от «Момента времени» к «Дате»

В подавляющем большинстве случаев для работы с виртуальной таблицей ОстаткиИОбороты использовать сложный тип данных МоментВремени в качестве параметров начала и конца периода не требуется. Достаточно использовать обычный тип данных Дата.

Рассмотрим особенности поведения виртуальной таблицы ОстаткиИОбороты:

Поэтому самым простым и надежным решением в консоли запросов будет:

  1. Очистить значения параметров &НачалоПериода и &КонецПериода в таблице параметров консоли.
  2. Установить для этих параметров простой тип Дата вместо «МоментВремени» или «Граница».
  3. Задать обычные текстовые значения дат, например, 07.01.2020 0:00:00 и 08.01.2020 23:59:59.

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


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

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(Объект.ДатаНачала));
// Обязательно приводим к концу дня для захвата всех движений последней секунды
Запрос.УстановитьПараметр("КонецПериода", КонецДня(Объект.ДатаОкончания)); 

Важнейший шаг: оптимизация производительности запроса

Обратим внимание на первоначальный запрос автора темы. Фильтрация данных по конкретному портфелю выполнялась в секции ГДЕ:


// Неоптимальный вариант запроса!
ВЫБРАТЬ
    АктивыОстаткиИОбороты.Портфель,
    АктивыОстаткиИОбороты.Инструмент,
    АктивыОстаткиИОбороты.КоличествоКонечныйОстаток
ИЗ
    РегистрНакопления.Активы.ОстаткиИОбороты(&НачалоПериода, &КонецПериода) КАК АктивыОстаткиИОбороты
ГДЕ
    АктивыОстаткиИОбороты.Портфель = &Портфель

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

Правильное решение: перенести отбор по измерению непосредственно в параметры виртуальной таблицы. В этом случае СУБД обратится к физическим таблицам итогов с уже наложенным фильтром по индексу. Расчет будет производиться только для одного конкретного портфеля, что ускорит выполнение запроса в десятки или сотни раз.

Давайте посмотрим, как выглядит правильный и оптимизированный запрос:


// Оптимальный вариант запроса с отбором в параметрах виртуальной таблицы
ВЫБРАТЬ
    АктивыОстаткиИОбороты.Портфель КАК Портфель,
    АктивыОстаткиИОбороты.Инструмент КАК Инструмент,
    АктивыОстаткиИОбороты.КоличествоНачальныйОстаток КАК КоличествоНачальныйОстаток,
    АктивыОстаткиИОбороты.КоличествоПриход КАК КоличествоПриход,
    АктивыОстаткиИОбороты.КоличествоРасход КАК КоличествоРасход,
    АктивыОстаткиИОбороты.КоличествоКонечныйОстаток КАК КоличествоКонечныйОстаток
ИЗ
    РегистрНакопления.Активы.ОстаткиИОбороты(
        &НачалоПериода, 
        &КонецПериода, , , 
        Портфель = &Портфель
    ) КАК АктивыОстаткиИОбороты

Обратите внимание на синтаксис параметров виртуальной таблицы ОстаткиИОбороты. Отбор передается в качестве пятого параметра конструкции: ОстаткиИОбороты(НачалоПериода, КонецПериода, Периодичность, МетодДополнения, УсловиеОтбора).

Автоматизация работы с периодами через СКД

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

СКД обладает мощным встроенным функционалом автоматического управления границами периодов:

← На главную