К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как указать период в запросе 1С

Как задать период в запросе 1С: через параметры даты, виртуальные таблицы регистров, конструкцию МЕЖДУ и функцию КОНЕЦПЕРИОДА. Примеры кода и типичные ошибки.

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

В языке запросов 1С период задаётся тремя основными способами: через параметры типа «Дата» в условии ГДЕ, через параметры виртуальных таблиц регистров (Остатки, Обороты, СрезПоследних) и через конструкцию МЕЖДУ. Каждый подход имеет свои тонкости с границами и производительностью.

Ниже разобраны все рабочие варианты с примерами кода, объяснено, почему «конец периода» часто работает не так, как ожидается, и как проверить, что запрос возвращает именно те данные, которые нужны.

Задание периода через параметры в условии ГДЕ

Базовый способ — передать в запрос два параметра типа «Дата» и сравнить с ними поле даты документа или регистра. Параметры объявляются в тексте запроса через символ амперсанда и заполняются методом УстановитьПараметр перед выполнением.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ

| Реализация.Ссылка,

| Реализация.Дата,

| Реализация.СуммаДокумента

|ИЗ

| Документ.РеализацияТоваровУслуг КАК Реализация

|ГДЕ

| Реализация.Дата МЕЖДУ &НачалоПериода И &КонецПериода

| И Реализация.Проведен";

Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));

Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));

Результат = Запрос.Выполнить();

Ключевой момент: тип «Дата» в 1С хранит время с точностью до секунды. Если пользователь выбрал дату окончания «31.03», её значение — 31.03 00:00:00, то есть начало суток. Все документы, созданные в течение 31 марта, окажутся за границей периода. Поэтому конец периода всегда приводят к концу дня функцией КонецДня() во встроенном языке или КОНЕЦПЕРИОДА в тексте запроса.

Конструкция МЕЖДУ и её особенности

Оператор МЕЖДУ включает обе границы: условие «Дата МЕЖДУ &Начало И &Конец» эквивалентно «Дата >= &Начало И Дата <= &Конец». Это удобно для читаемости, но требует аккуратности с конечной границей по той же причине с секундами.

Альтернатива — явные сравнения. Некоторые разработчики предпочитают полуоткрытый интервал «Дата >= &Начало И Дата < &КонецСледующегоДня», где в качестве конца передают начало следующего дня. Такой подход исключает неоднозначность с секундами и иногда удобнее при стыковке смежных периодов, чтобы граничное значение не попадало в оба диапазона.

Если нужен запрос без нижней или верхней границы (например, «все документы до даты»), просто опускают одно из условий. При этом фильтровать по дате стоит всегда, когда объём таблицы велик: отбор по индексированному полю даты существенно ускоряет выполнение.

Период в виртуальных таблицах регистров

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

ВЫБРАТЬ

Остатки.Номенклатура,

Остатки.КоличествоОстаток

ИЗ

РегистрНакопления.ТоварыНаСкладах.Остатки(&ДатаОстатков, ) КАК Остатки

У таблицы Остатки параметр один — момент, на который считаются остатки. Если передать дату без времени, остатки будут рассчитаны на начало этого дня, то есть движения за сам день не войдут. Чтобы получить остатки «на конец дня», передают КонецДня(Дата) либо используют объект Граница с видом «Включая».

У таблицы Обороты два первых параметра — начало и конец периода, далее идут периодичность и условия отбора:

ВЫБРАТЬ

Обороты.Номенклатура,

Обороты.КоличествоОборот

ИЗ

РегистрНакопления.Продажи.Обороты(&НачалоПериода, &КонецПериода, Месяц, ) КАК Обороты

Срез последних и срез первых в регистрах сведений

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

ВЫБРАТЬ

Курсы.Валюта,

Курсы.Курс

ИЗ

РегистрСведений.КурсыВалют.СрезПоследних(&ДатаКурса, ) КАК Курсы

Здесь действует то же правило границы: запись, сделанная в 15:30 указанного дня, не попадёт в срез, если параметр содержит начало суток. Если нужна позиция «на конец дня», передавайте КонецДня(Дата).

Дополнительный параметр после даты — условие отбора по измерениям, например «Валюта = &Валюта». Его стоит использовать вместо фильтра в ГДЕ: срез будет построен только для нужных записей.

Функции работы с периодом в тексте запроса

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

  • НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ) — приводит дату к началу указанного периода (день, неделя, месяц, квартал, год).
  • КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) — приводит к концу периода (23:59:59 для дня).
  • ДОБАВИТЬКДАТЕ(&Дата, МЕСЯЦ, 1) — сдвигает дату на заданное число единиц.
  • РАЗНОСТЬДАТ(&Начало, &Конец, ДЕНЬ) — вычисляет число единиц между датами.
ГДЕ

Документ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&ДатаОтчета, МЕСЯЦ)

И КОНЕЦПЕРИОДА(&ДатаОтчета, МЕСЯЦ)

Такой приём удобен, когда пользователь вводит одну произвольную дату, а отчёт должен показать весь месяц, в который она попадает. Не нужно вычислять границы в коде — запрос сделает это сам.

bsl
Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ДатаНачала));
Запрос.УстановитьПараметр("КонецПериода", КонецДня(ДатаОкончания));

Период в СКД и динамических списках

В системе компоновки данных период чаще всего оформляется как параметр типа «СтандартныйПериод» или «Дата». Стандартный период удобен тем, что пользователь выбирает готовые интервалы («этот месяц», «прошлый квартал»), а в запрос подставляются даты начала и окончания. Для этого в настройках СКД создают два параметра — НачалоПериода и КонецПериода — и связывают их со стандартным периодом через выражения.

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

В динамических списках форм период задаётся через свойство «Период» списка или через параметры произвольного запроса. Если список построен на произвольном запросе, границы периода нужно передавать параметрами так же, как в обычном запросе.

Типичные ошибки
01
Передача даты окончания без КонецДня — теряются все документы последнего дня после 00:00:00
02
Отбор по дате в ГДЕ вместо параметров виртуальной таблицы — запрос считается по всему регистру и работает медленно
03
Передача параметра строкой вместо типа Дата — сравнение не срабатывает или даёт неожиданный результат
04
Использование МЕЖДУ для стыковки смежных периодов — граничный документ попадает в оба отчёта

Проверка результата и типичные ошибки

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

Для отладки удобно использовать консоль запросов: она показывает фактические значения параметров и позволяет быстро менять границы. Обратите внимание на тип параметра — если вместо даты передана строка, сравнение может молча не сработать, и запрос вернёт пустой результат без ошибки.

Контрольные точки

Как проверить результат

Документ за последний день периода, проведённый днём
Норма

Попадает в выборку

Тревожный признак

Отсутствует — конец периода задан как начало суток

Документ первой секундой после периода
Норма

Не попадает в выборку

Тревожный признак

Попадает — граница сдвинута на лишние сутки

Скорость запроса по регистру
Норма

Период задан параметрами виртуальной таблицы

Тревожный признак

Отбор в ГДЕ, полное сканирование

Итог

Что важно запомнить

Период задаётся параметрами типа «Дата»: в ГДЕ — через МЕЖДУ или сравнения, в регистрах — через параметры виртуальных таблиц. Конец периода всегда приводите к концу дня (КонецДня или КОНЕЦПЕРИОДА), иначе потеряете последний день. Для виртуальных таблиц период указывайте в скобках, а не в ГДЕ — это и точнее, и быстрее.

Частые вопросы

Чем МЕЖДУ отличается от сравнений >= и <=?

По результату — ничем: «Дата МЕЖДУ &А И &Б» эквивалентно «Дата >= &А И Дата <= &Б» с включением обеих границ. Разница только в читаемости. Если нужен полуоткрытый интервал без верхней границы, МЕЖДУ не подойдёт — используйте явные сравнения.

Как получить остатки на конец дня, а не на начало?

Передайте в виртуальную таблицу Остатки значение КонецДня(Дата) — тогда в расчёт войдут все движения за этот день. Альтернатива — объект Граница с видом «Включая», построенный от момента времени последнего документа дня.

Почему запрос с СрезПоследних не видит запись, сделанную сегодня?

Потому что параметр даты содержит начало суток (00:00:00), а запись создана позже. Срез берёт записи не позже указанного момента. Передайте КонецДня(Дата) или ТекущаяДатаСеанса(), если нужен срез на текущий момент.

Можно ли задать период без параметров, прямо в тексте запроса?

Да, через литерал даты: ДАТАВРЕМЯ(2026, 3, 31, 23, 59, 59). Но так делать стоит только для отладки — в рабочем коде период всегда передают параметрами, чтобы запрос был универсальным и не требовал правки текста.

Как сгруппировать данные запроса по месяцам внутри периода?

Добавьте в выборку выражение НАЧАЛОПЕРИОДА(Документ.Дата, МЕСЯЦ) и сгруппируйте по нему. Для виртуальной таблицы Обороты проще: укажите третьим параметром периодичность «Месяц» — платформа сама разобьёт обороты по месяцам.

Что передавать, если пользователь не указал конец периода?

Либо не добавляйте условие по концу периода в текст запроса (формируйте текст динамически), либо передайте заведомо далёкую дату, например ДАТАВРЕМЯ(3999, 12, 31). Первый вариант предпочтительнее — он прозрачнее и не создаёт скрытых ограничений.