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