При разработке отчетов и обработок в среде 1С:Предприятие 8 разработчики часто сталкиваются с необходимостью получить курс валюты не на фиксированную дату отчета, а на дату совершения конкретной операции или документа (например, на дату начала договора, дату поступления актива или дату доведения НМА до состояния готовности). В этой статье разберем, почему стандартная виртуальная таблица среза последних не работает напрямую с динамическими датами строк, и рассмотрим правильные варианты решения этой задачи.
Виртуальная таблица РегистрСведений.КурсыВалют.СрезПоследних(&Период) принимает в качестве параметров только фиксированные значения (параметры запроса). Платформа 1С не позволяет передать в параметр &Период виртуальной таблицы поле из соединяемой строки (динамическую дату документа или договора).
Если мы попытаемся выполнить прямое соединение исходной таблицы с реальной таблицей РегистрСведений.КурсыВалют по условию КурсыВалют.Период <= Таблица.Дата и добавим поля Курс и Кратность в список выборки и группировки, запрос вернет не одну последнюю запись, а все исторические изменения курсов, произошедшие до этой даты. Это приведет к дублированию строк и искажению итоговых сумм.
Рассмотрим классический и наиболее производительный алгоритм получения среза данных на каждую строку таблицы при помощи языка запросов.
Разберем логику построения запроса по шагам:
РегистрСведений.КурсыВалют по условию соответствия валюты и КурсыВалют.Период <= ИсходнаяТаблица.Дата. На этом шаге выбираем ключевые поля исходной таблицы и вычисляем МАКСИМУМ(КурсыВалют.Период). Поля Курс и Кратность на данном этапе не выбираются и в группировку не включаются. Помещаем результат во временную таблицу.РегистрСведений.КурсыВалют, но уже по точному равенству двух полей: Валюта и Период = МаксимальныйПериод.Посмотрим на практический пример такого запроса:
ВЫБРАТЬ
ИтоговаяТаблица.ПрограммныйПродукт КАК ПрограммныйПродукт,
ИтоговаяТаблица.ЛицензионныйДоговор КАК ЛицензионныйДоговор,
ИтоговаяТаблица.ДатаДоведенияНМАДоСостоянияПригодногоДляИспользования КАК ДатаКурса,
ИтоговаяТаблица.СтоимостьСУчетомРусификации КАК СтоимостьСУчетомРусификации,
ИтоговаяТаблица.Валюта КАК Валюта,
МАКСИМУМ(КурсыВалют.Период) КАК МаксПериод
ПОМЕСТИТЬ ВТ_МаксимальныеДаты
ИЗ
ВТ_ИтоговаяТаблица КАК ИтоговаяТаблица
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
ПО (КурсыВалют.Валюта = ИтоговаяТаблица.Валюта)
И (КурсыВалют.Период <= ИтоговаяТаблица.ДатаДоведенияНМАДоСостоянияПригодногоДляИспользования)
СГРУППИРОВАТЬ ПО
ИтоговаяТаблица.ПрограммныйПродукт,
ИтоговаяТаблица.ЛицензионныйДоговор,
ИтоговаяТаблица.ДатаДоведенияНМАДоСостоянияПригодногоДляИспользования,
ИтоговаяТаблица.СтоимостьСУчетомРусификации,
ИтоговаяТаблица.Валюта
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
ВТ.ПрограммныйПродукт КАК ПрограммныйПродукт,
ВТ.ЛицензионныйДоговор КАК ЛицензионныйДоговор,
ВТ.ДатаКурса КАК ДатаДоведенияНМАДоСостоянияПригодногоДляИспользования,
ВТ.СтоимостьСУчетомРусификации КАК СтоимостьСУчетомРусификации,
ЕСТЬNULL(КурсыВалют.Курс, 1) КАК Курс,
ЕСТЬNULL(КурсыВалют.Кратность, 1) КАК Кратность
ИЗ
ВТ_МаксимальныеДаты КАК ВТ
ЛЕВОЕ СОЕДИНЕНИЕ РегистрСведений.КурсыВалют КАК КурсыВалют
ПО (КурсыВалют.Валюта = ВТ.Валюта)
И (КурсыВалют.Период = ВТ.МаксПериод)
Если отчет разрабатывается в Системе компоновки данных (СКД), можно избежать написания сложных конструкций с временными таблицами, воспользовавшись стандартным механизмом связей наборов данных.
Проанализируем порядок настройки СКД:
ВЫБРАТЬ
КурсыВалютСрезПоследних.Валюта КАК Валюта,
КурсыВалютСрезПоследних.Курс КАК Курс,
КурсыВалютСрезПоследних.Кратность КАК Кратность
ИЗ
РегистрСведений.КурсыВалют.СрезПоследних(&ПериодКурса, Валюта = &ВалютаКурса) КАК КурсыВалютСрезПоследних
НаборДанных1 источником связи, а НаборДанных2 — приемником. В выражении источника выбираем Валюта, в выражении приемника — Валюта.Для параметра ПериодКурса указываем поле ДатаДоведенияНМАДоСостоянияПригодногоДляИспользования.
Для параметра ВалютаКурса указываем поле Валюта.
При таком подходе СКД сама выполнит срез последних на каждую конкретную строку первого набора данных при формировании отчета.
Обратим внимание на несколько критически важных моментов при работе с курсами валют:
ЕСТЬNULL(КурсыВалют.Курс, 1) и ЕСТЬNULL(КурсыВалют.Кратность, 1), чтобы избежать пустых значений и ошибки деления на ноль при пересчете.ИНДЕКСИРОВАТЬ ПО Валюта, МаксПериод. Это оптимизирует выполнение второго соединения с регистром сведений.