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

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

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

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

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

Ключевая тонкость — тип даты в 1С хранит время с точностью до секунды. Значение КонецДня отличается от начала дня, и если передать в условие просто дату «31.01», запись, проведённая 31 января в 14:30, в выборку не попадёт. Именно поэтому в типовых конфигурациях верхняя граница почти всегда задаётся через функцию КонецПериода() или через объект Граница.

Ниже разобраны рабочие приёмы: передача параметров из кода, использование виртуальных таблиц регистров, включение и исключение граничных моментов, а также проверка результата и типичные ошибки, из-за которых отчёт «не видит» документы последнего дня периода.

Передача дат через параметры запроса

Базовый способ — объявить в тексте запроса параметры с символом «&» и установить их методом УстановитьПараметр() перед выполнением. Параметр может быть типа Дата (с указанием состава: дата, время или дата и время).

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

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

"ВЫБРАТЬ

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

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

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

|ИЗ

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

|ГДЕ

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

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

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

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

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

Обратите внимание на два приёма в примере. Во-первых, начало периода оборачивается в НачалоДня() — это гарантирует, что документы с нулевым временем и любым временем первого дня попадут в выборку. Во-вторых, конец периода задаётся через КонецДня(), то есть 23:59:59 последнего дня, иначе документы последнего дня с ненулевым временем будут потеряны.

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

Конструкция МЕЖДУ и сравнение границ

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

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

ГДЕ

| Продажи.Период >= &НачалоПериода

| И Продажи.Период < &НачалоСледующегоДня

Здесь НачалоСледующегоДня вычисляется как НачалоДня(ДатаОкончания + 86400). Такой вариант исключает двусмысленность с секундами и хорошо работает, если в будущем точность хранения дат изменится.

Способы задать конец периода

КонецДня(Дата)

Простой и понятный вариант для полей типа Дата документа. Ограничение: не подходит для сравнения с моментом времени документа, где важна позиция внутри секунды.

КонецПериода(Дата, День)

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

Объект Граница

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

Полуинтервал (Дата < СледующийДень)

Самый строгий вариант, не зависящий от точности секунд. Требует вычисления верхней границы в коде.

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

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

ВЫБРАТЬ

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

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

|ИЗ

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

У виртуальных таблиц «Остатки», «Обороты», «ОстаткиИОбороты» параметры периода идут первыми. Для «Оборотов» задаются начало и конец периода, а также периодичность (День, Месяц, Регистратор и т.д.). Для «Остатков» — один момент времени, на который считается остаток.

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

Тонкость с таблицей «Остатки»: если передать в параметр конец дня как дату, остаток будет рассчитан на этот момент, но движения, сделанные ровно в граничную секунду, могут трактоваться не так, как ожидается. Для точного контроля используйте объект Граница с видом «Включая» или «Исключая».

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

Объект Граница и момент времени

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

Типовой сценарий: нужно получить остатки на конец дня, включая все движения этого дня. Передают Новый Граница(КонецДня(Дата), ВидГраницы.Включая). Если же требуется остаток «на начало дня» без учёта движений текущего дня, используют Новый Граница(НачалоДня(Дата), ВидГраницы.Исключая).

В условии ГДЕ сравнение с моментом времени тоже возможно: Регистратор.МоментВремени > &Момент, где параметр — значение типа МоментВремени, полученное от документа. Это применяется при проведении документов «задним числом» и при построении последовательностей.

Выбор периода в консоли запросов и в СКД

Отладка в консоли запросов

При отладке в консоли запросов параметры периода заполняются вручную в таблице параметров. Указывайте тип «Дата» с составом «Дата и время» и вводите конец периода с временем 23:59:59 — иначе на этапе отладки получите неполную выборку и сделаете неверный вывод о работе запроса.

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

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

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

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

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

После написания запроса проверьте его на граничных данных. Создайте или найдите документы: ровно в 00:00:00 первого дня, в середине последнего дня и в 23:59:59 последнего дня. Все три должны попасть в выборку. Дополнительно сверьте итог с аналогичным типовым отчётом за тот же период — расхождение почти всегда означает ошибку в границах.

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

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

Документ последнего дня периода с временем, отличным от 00:00:00
Норма

Документ присутствует в выборке

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

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

Остатки на конец периода
Норма

Совпадают с типовым отчётом по регистру

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

Расхождение на сумму движений последнего дня — неверный вид границы

Скорость выполнения на большом регистре
Норма

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

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

Период в ГДЕ по физической таблице — читается весь регистр

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

Отдельная ситуация — необязательный период. Если пользователь может не задать даты, условие строят с проверкой: ГДЕ (&НачалоПериода = ДАТАВРЕМЯ(1,1,1) ИЛИ Таблица.Дата >= &НачалоПериода). Это позволяет одним текстом запроса обслуживать оба режима — с периодом и без.

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

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

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

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

Почему запрос не видит документы последнего дня периода?

Почти всегда причина в том, что конец периода передан как дата без времени, то есть 00:00:00 последнего дня. Условие <= отсекает всё, что проведено позже полуночи. Решение — обернуть дату в КонецДня() или КонецПериода(Дата, День) перед установкой параметра.

Где правильнее задавать период для регистра накопления?

В параметрах виртуальной таблицы — в скобках после её имени, например Обороты(&Начало, &Конец, Месяц, ). Тогда платформа читает только нужный диапазон. Фильтрация в ГДЕ по физической таблице заставляет прочитать регистр целиком и замедляет запрос в разы на больших объёмах.

Как получить остатки на конец дня, включая все движения этого дня?

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

Как сделать период необязательным параметром запроса?

Добавьте в условие проверку на пустое значение: ГДЕ (&НачалоПериода = ДАТАВРЕМЯ(1,1,1) ИЛИ Дата >= &НачалоПериода). Когда параметр не заполнен, условие по нему отключается, и запрос возвращает данные без ограничения по этой границе.

Влияет ли часовой пояс на отбор по периоду?

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

Итог

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

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