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