Как правильно передать дату документа в виртуальную таблицу регистра сведений внутри запроса?

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

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

Почему виртуальная таблица не принимает параметры из запроса?

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

Способ №1: Соединение с физической таблицей регистра

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

Разберем алгоритм действий:

  1. Соединяем таблицу документов с физической таблицей регистра ПДА по условию соответствия измерений (например, ЛицевойСчет).
  2. Добавляем условие, что Период регистра должен быть меньше или равен Событие.Дата.
  3. Группируем результат, чтобы найти для каждой пары (документ + лицевой счет) максимальную дату записи регистра.
  4. Полученный результат соединяем с физической таблицей еще раз (или используем вложенный запрос) для получения значений ресурсов на найденную дату.

Способ №2: Использование временных таблиц для оптимизации

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

  1. Выбираем все уникальные комбинации «ЛицевойСчет» и «Дата» из документов во временную таблицу.
  2. Используем эту таблицу как основу для поиска актуальных значений.
  3. Если регистр очень большой, можно сначала отобрать данные регистра только по интересующим нас лицевым счетам и диапазону дат, поместив их во вторую временную таблицу, и только потом производить соединение.

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

Вопросы хранения даты и времени

При сравнении дат документов и дат в регистре сведений часто возникает вопрос: нужно ли хранить время? Рассмотрим важные аспекты:

Важное предостережение: Никогда не сравнивайте поле с временем и поле без времени напрямую, так как это препятствует использованию индексов (индекс перестает быть SARGable). Это приводит к полному сканированию таблицы (Table Scan), что на больших объемах данных «подвесит» вашу систему.

Пример реализации

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


ВЫБРАТЬ
    Событие.ЛицевойСчет КАК ЛицевойСчет,
    Событие.Дата КАК ДатаСобытия,
    МаксПериод.МаксДата
ПОМЕСТИТЬ ВТ_МаксДаты
ИЗ Документ.Событие КАК Событие
ЛЕВОЕ СОЕДИНЕНИЕ (
    ВЫБРАТЬ
        ПДА.ЛицевойСчет КАК ЛицевойСчет,
        МАКСИМУМ(ПДА.Период) КАК МаксДата
    ИЗ РегистрСведений.ПДА КАК ПДА
    ГРУППИРОВАТЬ ПО ПДА.ЛицевойСчет
) КАК МаксПериод ПО Событие.ЛицевойСчет = МаксПериод.ЛицевойСчет
    И Событие.Дата >= МаксПериод.МаксДата
;

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

Использование этого подхода позволит вам точно сопоставить дату события и соответствующий срез регистра, обеспечив при этом высокую скорость работы запроса даже при значительном росте базы данных.

← На главную