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

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

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

Способ 1. Классический запрос через временную таблицу и соединение

Если данные хранятся в обычной таблице (например, в ТаблицеЗначений, переданной в запрос, или в физической таблице базы данных), мы не можем просто применить функцию Максимум() к курсу. Нам нужно сначала определить максимальную дату для каждой валюты, а затем «подтянуть» к этим датам соответствующие значения курсов.

Разберем алгоритм по шагам:

  1. Создаем временную таблицу, в которой группируем данные по валюте и находим максимальную дату.
  2. Соединяем эту временную таблицу с исходным источником данных по двум полям: по валюте и по дате.
  3. Выбираем из источника курс, соответствующий этой паре (Валюта + Максимальная дата).

Проанализируем пример кода такого запроса:


ВЫБРАТЬ
    Источник.Валюта КАК Валюта,
    МАКСИМУМ(Источник.Период) КАК МаксДата
ПОМЕСТИТЬ ВТ_ПоследниеДаты
ИЗ
    &ТаблицаКурсов КАК Источник
СГРУППИРОВАТЬ ПО
    Источник.Валюта
;

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

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

Способ 2. Использование виртуальной таблицы «СрезПоследних»

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

Рассмотрим, как это выглядит в коде:


ВЫБРАТЬ
    КурсыВалютСрезПоследних.Валюта,
    КурсыВалютСрезПоследних.Курс,
    КурсыВалютСрезПоследних.Кратность
ИЗ
    РегистрСведений.КурсыВалют.СрезПоследних(&Период, ) КАК КурсыВалютСрезПоследних

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

Способ 3. Оконные функции (для платформы 8.3.20 и выше)

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

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


ВЫБРАТЬ
    ВложенныйЗапрос.Валюта,
    ВложенныйЗапрос.Курс
ИЗ
    (ВЫБРАТЬ
        Источник.Валюта КАК Валюта,
        Источник.Курс КАК Курс,
        НОМЕР_СТРОКИ() НАД(ПАРТИЦИЯ ПО Источник.Валюта УПОРЯДОЧИТЬ ПО Источник.Период УБЫВ) КАК НомерЗаписи
    ИЗ
        &ТаблицаКурсов КАК Источник) КАК ВложенныйЗапрос
ГДЕ
    ВложенныйЗапрос.НомерЗаписи = 1

Использование ROW_NUMBER() (в синтаксисе 1С — НОМЕР_СТРОКИ()) делает код более читаемым и избавляет от необходимости соединять таблицы, что положительно сказывается на производительности при больших объемах данных.

Способ 4. Работа с данными в памяти (через «Соответствие»)

Если данные уже выгружены в ТаблицуЗначений и нам нужно программно (без запроса) оставить только последние значения, можно применить эффективный алгоритм с использованием объекта Соответствие (Map).

Разберем этот метод подробнее:

  1. Сначала отсортируем таблицу по дате в порядке возрастания.
  2. Создадим объект Соответствие.
  3. Обойдем таблицу циклом. В качестве ключа будем использовать валюту, в качестве значения — саму строку или курс.

Поскольку каждое новое значение в Соответствии по тому же самому ключу перезаписывает старое, после окончания цикла в объекте останутся только самые свежие данные.


ТаблицаКурсов.Сортировать("Период Возр");
ПоследниеКурсы = Новый Соответствие;

Для Каждого Строка Из ТаблицаКурсов Цикл
    ПоследниеКурсы.Вставить(Строка.Валюта, Строка.Курс);
КонецЦикла;

// Теперь мы можем быстро получить курс любой валюты
НужныйКурс = ПоследниеКурсы.Получить(ВыбраннаяВалюта);

Важные нюансы при работе с курсами

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

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

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

← На главную