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

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

При разработке отчетов и обработок в среде 1С:Предприятие 8 разработчики часто сталкиваются с необходимостью получить курс валюты не на фиксированную дату отчета, а на дату совершения конкретной операции или документа (например, на дату начала договора, дату поступления актива или дату доведения НМА до состояния готовности). В этой статье разберем, почему стандартная виртуальная таблица среза последних не работает напрямую с динамическими датами строк, и рассмотрим правильные варианты решения этой задачи.

В чем заключается сложность прямого соединения

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

Если мы попытаемся выполнить прямое соединение исходной таблицы с реальной таблицей РегистрСведений.КурсыВалют по условию КурсыВалют.Период <= Таблица.Дата и добавим поля Курс и Кратность в список выборки и группировки, запрос вернет не одну последнюю запись, а все исторические изменения курсов, произошедшие до этой даты. Это приведет к дублированию строк и искажению итоговых сумм.

Способ 1. Двухэтапный запрос через временную таблицу

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

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

  1. Получение максимальной даты курса: Соединяем исходную таблицу данных с физической таблицей регистра сведений РегистрСведений.КурсыВалют по условию соответствия валюты и КурсыВалют.Период <= ИсходнаяТаблица.Дата. На этом шаге выбираем ключевые поля исходной таблицы и вычисляем МАКСИМУМ(КурсыВалют.Период). Поля Курс и Кратность на данном этапе не выбираются и в группировку не включаются. Помещаем результат во временную таблицу.
  2. Получение ресурсов курса и кратности: Повторно соединяем полученную временную таблицу с физической таблицей регистра сведений РегистрСведений.КурсыВалют, но уже по точному равенству двух полей: Валюта и Период = МаксимальныйПериод.

Посмотрим на практический пример такого запроса:


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

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

Способ 2. Реализация через связь наборов данных в СКД

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

Проанализируем порядок настройки СКД:

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

    Для параметра ПериодКурса указываем поле ДатаДоведенияНМАДоСостоянияПригодногоДляИспользования.

    Для параметра ВалютаКурса указываем поле Валюта.

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

Важные рекомендации и оптимизация

Обратим внимание на несколько критически важных моментов при работе с курсами валют:

  1. Обработка национальной валюты: Если валюта взаиморасчетов совпадает с регламентированной валютой (рубли), в регистре курсов записей для нее обычно нет. Всегда используйте функцию ЕСТЬNULL(КурсыВалют.Курс, 1) и ЕСТЬNULL(КурсыВалют.Кратность, 1), чтобы избежать пустых значений и ошибки деления на ноль при пересчете.
  2. Индексация временных таблиц: При обработке больших объемов данных во временной таблице среза максимальных дат рекомендуется явно указывать директиву ИНДЕКСИРОВАТЬ ПО Валюта, МаксПериод. Это оптимизирует выполнение второго соединения с регистром сведений.
← На главную