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