Период в запросе 1С: параметры, виртуальные таблицы и СКД

· 9 мин

Содержание

Период в запросе 1С задают двумя параметрами: в тексте пишут &НачалоПериода и &КонецПериода, а в коде передают значения через Запрос.УстановитьПараметр(). Для документов условие ставят в ГДЕ ... МЕЖДУ, для регистров — в параметры виртуальной таблицы Обороты(&НачалоПериода, &КонецПериода, ...). Конец периода всегда доводят до 23:59:59 функцией КонецДня(), иначе последний день выпадет из выборки.

Типичная ситуация: отчёт по продажам за март показывает сумму меньше, чем в оборотно-сальдовой ведомости. Разница ровно в документах за 31 марта. Причина почти всегда одна — в параметр конца периода ушла дата 31.03 0:00:00. Ниже — как установить период в запросе правильно в каждом из типовых сценариев и где чаще всего ошибаются.

Базовый синтаксис: как задать период в тексте запроса

Запрос в 1С 8.3 не знает о «периоде» как отдельной сущности. Период — это просто две даты, которые вы сравниваете с полем Дата документа или Период регистра.

Минимальный рабочий пример для документов:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	РеализацияТоваровУслуг.Ссылка,
|	РеализацияТоваровУслуг.Дата,
|	РеализацияТоваровУслуг.СуммаДокумента
|ИЗ
|	Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
|	РеализацияТоваровУслуг.Дата МЕЖДУ &НачалоПериода И &КонецПериода
|	И РеализацияТоваровУслуг.Проведен";

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

Выборка = Запрос.Выполнить().Выбрать();

Что нужно знать про этот синтаксис:

  • 📌 МЕЖДУ включает обе границы. Это то же самое, что >= &НачалоПериода И <= &КонецПериода.
  • 📌 Имя параметра произвольное. &НачПер, &ДатаС, &Период1 — работают одинаково. Главное, чтобы имя в УстановитьПараметр() совпало с текстом.
  • 📌 Если параметр не установлен, при выполнении запроса будет ошибка. Пустое значение 1С не подставляет.
  • 📌 Регистр букв в названиях функций языка запросов не важен: МЕЖДУ и Между равнозначны.

Литерал даты прямо в тексте

Иногда нужна фиксированная дата, например для отладки в консоли запросов. Для этого есть функция ДАТАВРЕМЯ:

ГДЕ
	Док.Дата МЕЖДУ ДАТАВРЕМЯ(2025, 1, 1) И ДАТАВРЕМЯ(2025, 3, 31, 23, 59, 59)

В рабочем коде так не делают: дату вшивают в текст только для разовых проверок. Пустая дата записывается как ДАТАВРЕМЯ(1, 1, 1) — так удобно отсекать незаполненные поля.

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

Внутри запроса доступны функции, которые двигают дату к границе периода или сдвигают её. Они избавляют от лишнего кода в модуле.

ФункцияЧто делаетПример
НАЧАЛОПЕРИОДА(Дата, Вид)Дата начала дня, недели, месяца, квартала, годаНАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ)
КОНЕЦПЕРИОДА(Дата, Вид)Последняя секунда периодаКОНЕЦПЕРИОДА(&Дата, КВАРТАЛ)
ДОБАВИТЬКДАТЕ(Дата, Вид, N)Сдвиг на N единиц, N может быть отрицательнымДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -7)
РАЗНОСТЬДАТ(Д1, Д2, Вид)Разница между датами в единицахРАЗНОСТЬДАТ(Док.Дата, &Дата, ДЕНЬ)
ГОД, КВАРТАЛ, МЕСЯЦ, ДЕНЬИзвлекают часть даты числомМЕСЯЦ(Док.Дата) = 3

Вид периода пишется без кавычек: МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД, а для НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА ещё и ДЕКАДА, ПОЛУГОДИЕ.

Пример: передаёте одну дату, а запрос сам строит границы месяца.

ГДЕ
	Док.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ)

Функции применяйте к параметру, а не к полю таблицы. НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ) вычисляется один раз. НАЧАЛОПЕРИОДА(Док.Дата, МЕСЯЦ) = &Месяц вычисляется для каждой строки и не даёт использовать индекс по дате.

Функции над полем уместны в списке ВЫБРАТЬ — например, чтобы сгруппировать документы по месяцам:

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

Относительный период: «последние 30 дней», «прошлый месяц»

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

Текущую дату на сервере берут функцией ТекущаяДатаСеанса(). Она учитывает часовой пояс сеанса, поэтому в типовых конфигурациях её предпочитают ТекущаяДата().

Вариант 1: границы считаются в коде

Сегодня = ТекущаяДатаСеанса();

// Прошлый месяц целиком
НачПрошлогоМесяца = НачалоМесяца(ДобавитьМесяц(Сегодня, -1));
КонПрошлогоМесяца = КонецМесяца(НачПрошлогоМесяца);

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

Последние 30 дней включая сегодня: начало — НачалоДня(Сегодня) - 29 * 86400, конец — КонецДня(Сегодня). Дата в 1С хранится с точностью до секунды, поэтому прибавление числа сдвигает её на секунды: 86 400 — это сутки.

Вариант 2: границы считает сам запрос

ГДЕ
	Док.Дата МЕЖДУ НАЧАЛОПЕРИОДА(ДОБАВИТЬКДАТЕ(&ТекущаяДата, МЕСЯЦ, -1), МЕСЯЦ)
	           И КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(&ТекущаяДата, МЕСЯЦ, -1), МЕСЯЦ)

Передаёте один параметр ТекущаяДата. Удобно, когда текст запроса хранится в макете или в СКД и вы не хотите плодить параметры.

Нужный периодНачалоКонец
Текущий месяцНачалоМесяца(Сегодня)КонецМесяца(Сегодня)
Прошлый кварталНачалоКвартала(ДобавитьМесяц(Сегодня, -3))КонецКвартала(ДобавитьМесяц(Сегодня, -3))
С начала годаНачалоГода(Сегодня)КонецДня(Сегодня)
Последние 7 днейНачалоДня(Сегодня) - 6 * 86400КонецДня(Сегодня)

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

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

Обороты

ВЫБРАТЬ
	Продажи.Номенклатура,
	Продажи.Период,
	Продажи.КоличествоОборот,
	Продажи.СуммаОборот
ИЗ
	РегистрНакопления.Продажи.Обороты(
		&НачалоПериода,
		&КонецПериода,
		Месяц,
		Организация = &Организация) КАК Продажи

Параметры по порядку: начало, конец, периодичность, условие. Периодичность (Запись, Регистратор, День, Неделя, Месяц, Квартал, Год, Период, Авто) определяет, с каким шагом разобьются обороты. Значение Период означает одну строку на весь интервал — поле Период в выборке тогда недоступно.

Остатки и граница момента времени

Таблица Остатки принимает не интервал, а одну точку: Остатки(&МоментВремени, Условие). И здесь главная ловушка.

Остатки на дату 31.03.2025 0:00:00 — это остатки на начало 31 марта, без движений этого дня.

Если нужен остаток на конец дня, передайте КонецДня(Дата) или, надёжнее, границу с включением:

Граница = Новый Граница(КонецДня(Дата), ВидГраницы.Включая);
Запрос.УстановитьПараметр("МоментВремени", Граница);

Внутри документа остатки «на момент проведения» получают так: Новый Граница(Ссылка.МоментВремени(), ВидГраницы.Исключая). Тогда в остатки не попадут движения самого документа, и он не будет учитывать сам себя.

ОстаткиИОбороты

РегистрНакопления.ТоварыНаСкладах.ОстаткиИОбороты(
	&НачалоПериода,
	&КонецПериода,
	День,
	ДвиженияИГраницыПериода,
	Склад = &Склад)

Четвёртый параметр — метод дополнения. Движения выводит только дни, в которых были движения. ДвиженияИГраницыПериода добавляет строки на начало и конец интервала, даже если движений там не было: так начальный остаток периода не теряется.

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

РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Дата, ВидЦены = &ВидЦены)

Здесь тоже одна точка. Срез на 0:00:00 не увидит цену, установленную в тот же день в 10:00. Передавайте КонецДня(Дата), если нужна цена на конец дня.

Таблица соответствий

ТаблицаЧто передаётсяГде ошибаются
Оборотыначало и конецконец без КонецДня
Остаткиодна точкадата без времени — остаток на начало дня
ОстаткиИОборотыначало, конец, периодичность, методнет строк за дни без движений
СрезПоследних / СрезПервыходна точкадата без времени

Период из формы и из схемы компоновки данных

В пользовательском интерфейсе период обычно выбирают одним полем типа СтандартныйПериод. У него есть свойства ДатаНачала, ДатаОкончания и Вариант (например, ВариантСтандартногоПериода.ЭтотМесяц).

Форма обработки или отчёта на запросе

  1. Добавьте реквизит формы с типом СтандартныйПериод, например Период.
  2. Перетащите его на форму — платформа покажет поле с кнопкой выбора периода.
  3. В серверной процедуре передайте даты в запрос:
&НаСервере
Процедура СформироватьНаСервере()
	Запрос = Новый Запрос(ТекстЗапроса());
	Запрос.УстановитьПараметр("НачалоПериода", Период.ДатаНачала);
	Запрос.УстановитьПараметр("КонецПериода", КонецДня(Период.ДатаОкончания));
	Результат = Запрос.Выполнить();
	// вывод результата
КонецПроцедуры

ДатаОкончания у стандартного периода, выбранного в диалоге, уже содержит 23:59:59. Но если пользователь не выбирал период, дата будет пустой. КонецДня() ничего не портит, поэтому вызывать его лучше всегда.

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

Схема компоновки данных

В СКД периодом управляют параметры компоновки. Если в тексте набора данных есть &НачалоПериода и &КонецПериода, конструктор создаст их на закладке «Параметры» сам.

Практичная схема, которую используют в типовых отчётах:

  1. На закладке «Параметры» добавьте параметр Период с типом Стандартный период.
  2. Параметрам НачалоПериода и КонецПериода пропишите в колонке «Выражение» &Период.ДатаНачала и &Период.ДатаОкончания.
  3. Снимите им флажок доступности пользователю — пользователь видит только одно поле «Период».
  4. Для Период включите «Включать в пользовательские настройки», чтобы поле вышло в шапку отчёта.

Для дат в СКД доступны типы стандартной даты начала: значение по умолчанию «Начало этого месяца», «Начало этого года» и подобные. Это относительный период без единой строки кода.

В тексте запроса СКД параметры виртуальных таблиц можно обернуть в фигурные скобки:

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

Фигурные скобки делают параметр необязательным: если значение не задано, компоновщик выбросит условие, а не упадёт с ошибкой.

Как ускорить запрос с периодом

Медленный отчёт за год почти всегда связан с тем, где и как стоит условие на дату.

  • ⚡ Условие в параметрах виртуальной таблицы, а не в ГДЕ. Параметры виртуальной таблицы отбирают данные до свёртки и могут использовать итоги регистра. Условие в ГДЕ срабатывает уже после того, как таблица собрана за всё время.
  • ⚡ Без функций над полем даты. ГОД(Док.Дата) = 2025 — полный просмотр таблицы. Док.Дата МЕЖДУ &Нач И &Кон — поиск по индексу.
  • ⚡ Периодичность не мельче нужной. Запись или Регистратор дают по строке на каждое движение. Для отчёта по месяцам ставьте Месяц.
  • ⚡ Узкий интервал. Отчёт «за всё время» по большому регистру — это сотни тысяч строк. Задайте период по умолчанию в форме или СКД.
  • ⚡ Временные таблицы. Если один и тот же отбор по периоду нужен в нескольких частях пакета, сохраните его в ПОМЕСТИТЬ ВТ_Документы и проиндексируйте по ключевому полю.

Сравнение двух вариантов одного запроса:

// Медленно: остатки за всё время, отбор потом
ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки() КАК Ост
ГДЕ Ост.Склад = &Склад

// Быстро: отбор внутри виртуальной таблицы
ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(&МоментВремени, Склад = &Склад) КАК Ост

Для «пустых» периодов, когда нужен месяц в выборке даже без продаж, используйте итоги с дополнением:

ИТОГИ СУММА(СуммаОборот) ПО
	Период ПЕРИОДАМИ(МЕСЯЦ, &НачалоПериода, &КонецПериода)

Обходите такую выборку вызовом Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам, "Период", "Все"): третий параметр "Все" выводит строки и для месяцев без данных.

Ошибки при установке периода и что с ними делать

Диагностика: выберите симптом

Отдельно про часовые пояса. Если сервер и пользователи работают в разных поясах, ТекущаяДата() вернёт время сервера. Для периода «сегодня» используйте ТекущаяДатаСеанса(), иначе после полуночи по Москве у пользователя в Новосибирске отчёт может захватить не тот день.

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

Можно ли передать в запрос сразу СтандартныйПериод одним параметром?
В тексте обычного запроса — нет, язык запросов не умеет обращаться к свойствам параметра. Передайте ДатаНачала и ДатаОкончания двумя параметрами. В СКД обращение &Период.ДатаНачала работает в выражении параметра.
Чем КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) в запросе отличается от КонецДня() в коде?
Результат одинаковый — 23:59:59 того же дня. Разница только в том, где считается граница: в тексте запроса или в модуле. Выбирайте один способ и придерживайтесь его во всём отчёте.
Как отобрать документы за конкретный месяц, не зная его границ?
Передайте любую дату этого месяца и используйте условие Док.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ). Это быстрее, чем МЕСЯЦ(Док.Дата) = 3 И ГОД(Док.Дата) = 2025.
Можно ли указать период для запроса к справочнику?
У справочника нет поля даты, поэтому период к нему напрямую не применить. Отбирают по дате связанной таблицы: документов, регистра или реквизита-даты, если он есть в справочнике.
Как сравнить два периода в одном запросе, например март и март прошлого года?
Сделайте два обращения к виртуальной таблице с разными параметрами (&Нач1, &Кон1 и &Нач2, &Кон2) и объедините их через ОБЪЕДИНИТЬ ВСЕ с колонками «Сумма текущая» и «Сумма прошлая», затем сгруппируйте.