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

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

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

Проанализируем ситуацию. Допустим, в регистре сведений КурсыВалют есть следующие записи:

Мы хотим, чтобы в отчете данные отображались корректно: с 1 по 14 февраля курс был 15 рублей, с 15 по 27 февраля — 25 рублей, а с 28 февраля — 35 рублей. Рассмотрим несколько способов решения этой задачи, от самого простого к более сложному.

Способ 1: Использование дополнения периода в настройках СКД

Это самый простой и быстрый метод, который не требует изменения текста запроса. Вся магия происходит в настройках самой компоновки данных. Механизм дополнения периода позволяет СКД автоматически "достроить" недостающие даты в выбранном интервале и подставить для них последние актуальные значения.

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

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

    
    ВЫБРАТЬ
        КурсыВалют.Период КАК Период,
        КурсыВалют.Валюта КАК Валюта,
        КурсыВалют.Курс КАК Курс
    ИЗ
        РегистрСведений.КурсыВалют КАК КурсыВалют
    
  2. Переходим в настройки СКД. Откройте схему компоновки данных и перейдите на вкладку "Настройки".

  3. Настраиваем дополнение для поля периода. В структуре отчета выделите группировку по полю Период или, если ее нет, перейдите на вкладку "Другие настройки". Здесь для поля Период (или любого поля с типом Дата, по которому нужно дополнение) найдите свойство "Дополнение периода".

  4. Устанавливаем тип дополнения. В свойстве "Дополнение периода" выберите значение "День". Также можно указать границы дополнения, если это необходимо (например, начало и конец периода из параметров отчета).

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

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

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

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

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

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

  2. Соединяем с виртуальной таблицей. Полученную таблицу дат мы соединяем с виртуальной таблицей РегистрСведений.КурсыВалют.СрезПоследних. Ключевой момент — соединение происходит по условию, что дата из календаря является параметром "Период" для среза. Таким образом, для каждой даты мы получаем свой собственный срез.

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


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

В этом более сложном, но универсальном примере, мы сначала создаем временную таблицу ВТ_Календарь со всеми датами. Затем, с помощью ЛЕВОЕ СОЕДИНЕНИЕ, присоединяем к каждой дате актуальный курс, полученный через СрезПоследних. Условие среза Валюта = &Валюта позволяет фильтровать данные по конкретной валюте, переданной в параметрах отчета.

Преимущества этого подхода:

Способ 3: Сложный запрос с временными таблицами и самосоединением

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

Идея в том, чтобы для каждой записи о курсе найти дату установки предыдущего курса. Таким образом, мы получим интервалы ("С даты", "По дату"), в течение которых действовало каждое значение.

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


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

Как это работает:

  1. Первый пакет копирует все записи о курсах во временную таблицу ВТ_Курсы.
  2. Второй пакет — самый главный. Он соединяет таблицу ВТ_Курсы саму с собой. Для каждой даты (ВТ_Курсы.Период) он ищет все предыдущие даты (ВТ_Курсы1.Период) и с помощью функции МАКСИМУМ находит самую последнюю из них. Эта дата и будет началом периода действия курса.
  3. Третий пакет соединяет полученные интервалы с курсами, чтобы получить итоговый результат.

Недостатки этого подхода:

Итоги и рекомендации

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

  1. Дополнение периода в настройках СКД: Самый простой и быстрый способ. Идеален для простых отчетов, где не требуется сложная логика в запросе. Рекомендуется как решение "по умолчанию".
  2. Виртуальная таблица СрезПоследних: Самый правильный и производительный способ. Обеспечивает максимальную гибкость и контроль. Является стандартом для работы с периодическими данными в 1С.
  3. Запрос с временными таблицами: Сложный и потенциально медленный способ. Следует использовать только в исключительных случаях, когда стандартные механизмы не подходят.

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

← На главную