Как получить курс валюты из регистра сведений на дату каждого документа в запросе 1С

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

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

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

Почему не работает «простой» запрос?

Многие начинающие разработчики пытаются написать запрос следующим образом:


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

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

Способ 1. Классический трехшаговый метод (через временные таблицы)

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

Шаг 1. Сбор уникальных комбинаций. Проанализируем наши данные и соберем во временную таблицу все уникальные пары «Дата + Валюта», для которых нам нужен курс. Это важно для оптимизации: если у нас 1000 документов за один день по одной валюте, нам нужно найти курс в регистре всего один раз, а не 1000.


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

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


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

Шаг 3. Получение финальных данных. Теперь, когда у нас есть таблица ВТ_СвязиКурсов, где четко указано, какой дате документа какая дата записи регистра соответствует, мы соединяем её с физической таблицей регистра и нашими документами.


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

    ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
    ПО Связи.Валюта = КурсыВалют.Валюта
    И Связи.ПериодКурса = КурсыВалют.Период

Способ 2. Использование Системы Компоновки Данных (СКД)

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

  1. Создадим Набор данных 1 (запрос), в котором выберем все данные документов (Ссылку, Дату, Валюту и т.д.).
  2. Создадим Набор данных 2 (запрос), который обращается к виртуальной таблице РегистрСведений.КурсыВалют.СрезПоследних(&Период, Валюта = &Валюта).
  3. Перейдем на вкладку Связи наборов данных.
  4. Настроим связь от Набора 1 к Набору 2. В колонке «Источник связи» укажем Валюта и Дата (из документов). В колонке «Параметры» для связи по дате укажем параметр Период, а для связи по валюте — параметр Валюта.

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

Способ 3. Интервальный метод

Проанализируем ситуацию, когда данных очень много. Существует подход, при котором в запросе для каждой записи курса вычисляется «дата окончания» действия этого курса. Это позволяет использовать простое соединение с условием МЕЖДУ.

Для этого во временной таблице для каждой записи регистра сведений с помощью подзапроса или соединения вычисляется период следующей записи. В итоге получается структура: Валюта | Курс | ДатаНачала | ДатаОкончания. Соединение документов с такой таблицей выглядит так:


ЛЕВОЕ СОЕДИНЕНИЕ ВТ_ИнтервалыКурсов КАК Курсы
ПО Реализация.Валюта = Курсы.Валюта
И Реализация.Дата МЕЖДУ Курсы.ДатаНачала И Курсы.ДатаОкончания

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

Рекомендации по оптимизации

Работа с регистрами сведений в запросах требует внимания к деталям, особенно при использовании PostgreSQL:

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

← На главную