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

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

В практике разработчика 1С часто возникает задача получить в результате запроса полный список дат за определенный период, даже если в базе данных за эти дни нет никаких движений или записей. Это необходимо для построения отчетов, где нужно выводить нулевые показатели, или для корректного соединения с виртуальными таблицами остатков. При поиске расхождений между базами после миграции или обмена автоматическая сверка бухгалтерских и налоговых проводок через COM-соединение сокращает время на ручной анализ. Рассмотрим подробнее несколько проверенных способов решения этой задачи — от простых и быстрых до универсальных и высокопроизводительных.

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

Разберем самый простой вариант. Если в вашей конфигурации ведется РегистрСведений.РегламентированныйПроизводственныйКалендарь (или ДанныеПроизводственногоКалендаря в более новых версиях БСП), мы можем напрямую обратиться к нему. Это наиболее эффективный метод, так как мы используем уже готовую таблицу с датами.

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


ВЫБРАТЬ
    Календарь.ДатаКалендаря КАК Период
ИЗ
    РегистрСведений.РегламентированныйПроизводственныйКалендарь КАК Календарь
ГДЕ
    Календарь.ДатаКалендаря МЕЖДУ &НачалоПериода И &КонецПериода
УПОРЯДОЧИТЬ ПО
    Период

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

Способ 2: Генерация дат через таблицу чисел (Декартово произведение)

Выясним, что делать, если производственный календарь недоступен или не заполнен. Рассмотрим классический метод формирования дат «на лету» с помощью объединения цифр. Мы создаем виртуальную таблицу с цифрами от 0 до 9 и соединяем ее саму с собой несколько раз, получая разряды (единицы, десятки, сотни и т.д.).

Посмотрим на пример реализации, который позволяет получить список из 1000 дат (что покрывает почти 3 года):


ВЫБРАТЬ 0 КАК Цифра ПОМЕСТИТЬ ВТ_Цифры ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4 
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 7 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, т100.Цифра * 100 + т10.Цифра * 10 + т1.Цифра) КАК Период
ИЗ
    ВТ_Цифры КАК т1
    СОЕДИНЕНИЕ ВТ_Цифры КАК т10 ПО (ИСТИНА)
    СОЕДИНЕНИЕ ВТ_Цифры КАК т100 ПО (ИСТИНА)
ГДЕ
    ДОБАВИТЬКДАТЕ(&НачалоПериода, ДЕНЬ, т100.Цифра * 100 + т10.Цифра * 10 + т1.Цифра) <= &КонецПериода
УПОРЯДОЧИТЬ ПО
    Период

Разберем по шагам, как это работает. Мы используем функцию ДОБАВИТЬКДАТЕ, где третьим параметром выступает число, полученное из комбинации разрядов. Преимущество метода заключается в его полной автономности: он будет работать в любой базе данных 1С независимо от настроек календаря.

Если нам нужно получить даты за 27 лет (около 10 000 дней), достаточно добавить еще одно соединение (т1000). Для повышения производительности рекомендуется сначала отобрать нужное количество чисел во временную таблицу, а уже потом применять функцию ДОБАВИТЬКДАТЕ. Для рассмотрения альтернативных вариантов построения выборки диапазона чисел или дат можно изучить методику генерации интервалов в запросах 1С.

Способ 3: Метод итогов с дополнением периодов

Проанализируем еще один интересный механизм языка запросов — ИТОГИ ПО ... ПЕРИОДАМИ. Этот способ кажется самым коротким, но у него есть критическое ограничение: его нельзя использовать во вложенных запросах.

Рассмотрим пример кода:


ВЫБРАТЬ
    &НачалоПериода КАК Период
ИТОГИ ПО
    Период ПЕРИОДАМИ(ДЕНЬ, &НачалоПериода, &КонецПериода)

При обходе результата такого запроса в коде 1С необходимо использовать специальный метод выборки:


Выборка = РезультатЗапроса.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "ВСЕ");
Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Период);
КонецЦикла;

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

Способ 4: Оптимизированная генерация больших интервалов

Посмотрим на более современную и «прочную» версию генерации через временные таблицы. Чтобы не перегружать запрос лишними соединениями (ПО ИСТИНА), можно использовать условие в ГДЕ, которое ограничит выборку еще на этапе декартова произведения.

Рассмотрим вариант для получения списка месяцев:


ВЫБРАТЬ 0 КАК Цифра ПОМЕСТИТЬ ВТ_Цифры ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 1 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 2 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 3 
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 4 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 5 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 6 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 7 
ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 8 ОБЪЕДИНИТЬ ВСЕ ВЫБРАТЬ 9;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&НачалоПериода, МЕСЯЦ, т1.Цифра + т10.Цифра * 10 + т100.Цифра * 100), МЕСЯЦ) КАК Месяц
ИЗ
    ВТ_Цифры КАК т1,
    ВТ_Цифры КАК т10,
    ВТ_Цифры КАК т100
ГДЕ
    т1.Цифра + т10.Цифра * 10 + т100.Цифра * 100 <= РАЗНОСТЬДАТ(&НачалоПериода, &КонецПериода, МЕСЯЦ)

В данном примере мы используем функцию РАЗНОСТЬДАТ, чтобы точно определить верхний предел счетчика. Это позволяет избежать лишних итераций и делает запрос более надежным.

Какой метод выбрать?

Подведем итоги и проанализируем, когда и какой способ лучше применять:

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

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

← На главную