Разработка и Конфигурация · 10 мин
Как в запросе 1С сделать отбор по дате
Разбираем отбор по дате в запросе 1С: параметры, периоды, функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА, пустая дата, виртуальные таблицы и частые ошибки.
Отбор по дате — одна из самых частых операций в запросах 1С: выбрать документы за период, посчитать остатки на конец месяца, получить срез последних. При этом именно с датами связано больше всего ошибок: неправильные границы периода, потеря документов на границе дня, медленная работа из-за функций в условии. Ниже разобраны рабочие приёмы с примерами кода на языке запросов 1С.
Базовый принцип: дату в условие ГДЕ лучше передавать через параметр, а не подставлять строкой в текст запроса. Это защищает от ошибок форматирования, ускоряет выполнение (запрос кэшируется) и делает код читаемым. Для границ периода используются функции языка запросов НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА, а для выборок «на дату» — виртуальные таблицы с параметром периода.
Простой отбор по конкретной дате через параметр
Самый простой случай — выбрать документы за конкретный день или сравнить дату с переданным значением. Дата передаётся в запрос через Запрос.УстановитьПараметр():
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Реализация.Ссылка,
| Реализация.Дата,
| Реализация.СуммаДокумента
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Реализация
|ГДЕ
| Реализация.Дата >= &НачалоДня
| И Реализация.Дата <= &КонецДня";
Запрос.УстановитьПараметр("НачалоДня", НачалоДня(ТекущаяДата()));
Запрос.УстановитьПараметр("КонецДня", КонецДня(ТекущаяДата()));
Результат = Запрос.Выполнить().Выбрать();
Обратите внимание: сравнение Дата = &Дата почти никогда не даёт результата, потому что дата документа хранится с точностью до секунды. Совпадение до секунды — редкость, поэтому для «конкретного дня» всегда используйте диапазон от начала до конца дня.
Отбор за период: МЕЖДУ и границы интервала
Для выборки за произвольный период удобен оператор МЕЖДУ. Он включает обе границы, поэтому важно правильно задать конец периода — иначе документы последнего дня потеряются:
Запрос.Текст =
"ВЫБРАТЬ
| Поступление.Ссылка,
| Поступление.Дата
|ИЗ
| Документ.ПоступлениеТоваровУслуг КАК Поступление
|ГДЕ
| Поступление.Дата МЕЖДУ &НачалоПериода И &КонецПериода
| И Поступление.Проведен";
Типичная ошибка — передать в КонецПериода дату без времени, например '20260131'. Такая дата равна 31.01.2026 00:00:00, и все документы за 31 января, проведённые после полуночи (то есть практически все), в выборку не попадут. Правильные варианты: передать КонецДня(ДатаОкончания) из кода или использовать функцию КОНЕЦПЕРИОДА прямо в тексте запроса.
Функции НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА
Язык запросов позволяет вычислить границу периода прямо в тексте, не передавая лишние параметры. Синтаксис: НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ), вторым аргументом указывается тип периода — СЕКУНДА, МИНУТА, ЧАС, ДЕНЬ, НЕДЕЛЯ, МЕСЯЦ, КВАРТАЛ, ГОД.
Запрос.Текст =
"ВЫБРАТЬ
| Заказ.Ссылка,
| Заказ.Дата
|ИЗ
| Документ.ЗаказПокупателя КАК Заказ
|ГДЕ
| Заказ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ)
| И КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ)";
Запрос.УстановитьПараметр("Дата", Дата(2026, 3, 15));
В примере достаточно передать одну дату — запрос сам выберет весь март. Это удобно в отчётах, где пользователь указывает «месяц в целом», а не точные границы. Аналогично строятся выборки «за неделю», «за квартал», «за год».
Отбор «до даты» и «после даты»
Если нужна выборка без одной из границ, используйте обычные операторы сравнения: Дата < &Дата (все документы строго раньше указанного момента) или Дата >= &Дата (начиная с даты включительно). Помните, что условие Дата <= &Дата с датой без времени фактически означает «до начала этого дня».
Отбор по пустой дате
Пустая дата в 1С — это значение '0001-01-01 00:00:00'. Отобрать записи, где дата не заполнена, можно двумя способами: сравнением с параметром или функцией ЗНАЧЕНИЕ:
ГДЕ
| Документ.ДатаОплаты = &ПустаяДата
// или
| Документ.ДатаОплаты = ДАТАВРЕМЯ(1, 1, 1)
Функция ДАТАВРЕМЯ(год, месяц, день, часы, минуты, секунды) — удобный способ задать литерал даты прямо в запросе без параметра. Например, ДАТАВРЕМЯ(2026, 1, 1) — начало 2026 года. Это полезно для фиксированных границ в типовых отчётах.
Отбор «на дату»: виртуальные таблицы регистров
Когда нужны не документы, а данные на момент времени (остатки, срез последних, цены), отбор по дате задаётся через параметры виртуальной таблицы, а не через ГДЕ. Это принципиально важно: условие в ГДЕ применится после выборки и не даст нужного результата.
Запрос.Текст =
"ВЫБРАТЬ
| Остатки.Номенклатура,
| Остатки.КоличествоОстаток
|ИЗ
| РегистрНакопления.ТоварыНаСкладах.Остатки(&Период, Склад = &Склад) КАК Остатки";
Запрос.УстановитьПараметр("Период", КонецДня(ДатаОтчета));
Аналогично для регистра сведений: РегистрСведений.ЦеныНоменклатуры.СрезПоследних(&Период, ) вернёт актуальные цены на указанный момент. Параметр периода у виртуальных таблиц работает как «включительно слева, строго до» или «на конец» в зависимости от таблицы — для СрезПоследних дата включается в срез.
Сравнение даты с текущей и вычисления с датами
Для сравнения с текущим моментом используется функция &ТекущаяДата, переданная параметром из кода (ТекущаяДатаСеанса() — предпочтительный вариант, корректно работает с часовыми поясами сервера). В самом языке запросов есть функция ТЕКУЩАЯДАТА(), но в тонком клиенте и веб-клиенте она берёт время клиентского компьютера, что может расходиться с серверным.
Для арифметики с датами служит функция ДОБАВИТЬКДАТЕ(&Дата, ДЕНЬ, -7) — например, «документы за последние 7 дней». А РАЗНОСТЬДАТ(Дата1, Дата2, ДЕНЬ) позволяет отобрать просроченные документы, где разница между текущей датой и датой оплаты больше заданного срока.
ГДЕ РАЗНОСТЬДАТ(Документ.ДатаОплаты, &ТекущаяДата, ДЕНЬ) > 30Как проверить, что отбор работает правильно
После написания запроса проверьте его на граничных данных: документе ровно в 00:00:00 первого дня, документе в 23:59:59 последнего дня и документе за пределами периода. Консоль запросов (типовая в режиме предприятия или внешняя обработка) позволяет выполнить запрос с конкретными параметрами и увидеть результат до встраивания в код.
Дополнительная проверка — сравнить количество строк в результате с тем, что показывает стандартный отчёт или список документов с тем же отбором по периоду. Расхождение обычно указывает на ошибку в границах периода или на лишние условия (например, отбор по Проведен, которого нет в интерфейсном списке).
Как проверить результат
Попадает в выборку
Отсутствует — конец периода задан без времени
Попадает в выборку
Отсутствует — начало периода сдвинуто
Совпадает со списком документов с тем же отбором
Меньше — проверьте границы и лишние условия
Производительность: где ставить условие по дате
Отбор по дате влияет на скорость запроса. Правила простые: условие по дате ставьте как можно раньше — в параметры виртуальной таблицы или в условие соединения, а не в итоговое ГДЕ после соединений. Чем меньше строк обрабатывается на каждом шаге, тем быстрее запрос.
Избегайте применения функций к полю даты в условии: конструкция НАЧАЛОПЕРИОДА(Документ.Дата, ДЕНЬ) = &Дата отключает использование индекса по дате и заставляет СУБД сканировать всю таблицу. Перепишите её как диапазон: Документ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ) И КОНЕЦПЕРИОДА(&Дата, ДЕНЬ) — функции применяются к параметру, а не к полю таблицы.
Сравнение вариантов
Универсальный вариант для документов за период. Быстро работает, использует индекс по дате.
Удобно, когда задана одна дата, а нужен целый месяц или день. Применять к параметру, не к полю таблицы.
Единственный правильный способ для остатков и срезов на дату. Не заменяется условием ГДЕ.
Подходит для фиксированных границ и пустой даты, когда параметр избыточен.
Ответы на частые вопросы
Почему условие Дата = &Дата не находит документы?
Поле Дата документа содержит время с точностью до секунды, а переданная дата обычно равна 00:00:00. Совпадение возможно только при точном совпадении секунды. Замените равенство на диапазон: Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ) И КОНЕЦПЕРИОДА(&Дата, ДЕНЬ).
Как выбрать документы за последние 30 дней?
Передайте параметр ТекущаяДата и используйте условие: Документ.Дата >= ДОБАВИТЬКДАТЕ(&ТекущаяДата, ДЕНЬ, -30). Если нужны полные календарные дни, дополнительно оберните границу в НАЧАЛОПЕРИОДА(..., ДЕНЬ).
Как отобрать записи, где дата не заполнена?
Сравните поле с пустой датой: Поле = ДАТАВРЕМЯ(1, 1, 1) или передайте параметр со значением '00010101'. Проверка через ЕСТЬ NULL не равнозначна: NULL возникает при соединениях, а пустая дата — это конкретное значение 01.01.0001.
Чем отличается период в параметрах виртуальной таблицы от условия ГДЕ?
Параметр виртуальной таблицы определяет, на какой момент вычисляются остатки или срез. Условие ГДЕ фильтрует уже полученный результат. Для Остатков и СрезаПоследних период нужно указывать только в параметрах, иначе данные будут рассчитаны на текущий момент.
Можно ли отобрать документы по месяцу без указания точных границ?
Да. Передайте одну дату и напишите: Документ.Дата МЕЖДУ НАЧАЛОПЕРИОДА(&Дата, МЕСЯЦ) И КОНЕЦПЕРИОДА(&Дата, МЕСЯЦ). Запрос сам вычислит первое и последнее число месяца, включая всё последнее число до 23:59:59.
Почему запрос с отбором по дате работает медленно?
Частая причина — функция применена к полю таблицы в условии (например, НАЧАЛОПЕРИОДА(Дата, ДЕНЬ) = &Дата), что отключает индекс. Перепишите условие как диапазон по полю Дата. Также проверьте, не стоит ли условие по дате после соединений вместо параметров виртуальной таблицы.
Что важно запомнить
Дату передавайте параметром, конкретный день задавайте диапазоном от начала до конца дня, границы вычисляйте функциями НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА. Для остатков и срезов период указывайте только в параметрах виртуальной таблицы. Проверяйте результат на граничных документах — 00:00:00 первого и 23:59:59 последнего дня.