Как правильно выбрать документы за конкретную дату в запросе 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При работе с платформой 1С:Предприятие начинающие разработчики часто сталкиваются с ситуацией, когда обычное сравнение даты в запросе (например, Реал.Дата = &Дата) не возвращает ожидаемые результаты. Проблема заключается в том, что тип данных Дата в 1С всегда содержит время. Если в параметре передана дата с временем 00:00:00, запрос найдет только те документы, которые были созданы ровно в полночь. Все остальные документы, созданные в течение дня, будут проигнорированы.

В этой статье мы подробно разберем, как выбрать все документы за определенные сутки, рассмотрим различные способы реализации этой задачи и проанализируем нюансы производительности.

Способ 1. Использование оператора МЕЖДУ и функций периода

Самый простой и эффективный способ выбрать данные за день — это задать интервал, охватывающий все время от начала до конца нужных суток. Для этого в языке запросов 1С используется оператор МЕЖДУ в сочетании с функциями НАЧАЛОПЕРИОДА и КОНЕЦПЕРИОДА.

Давайте рассмотрим пример текста запроса, который решает эту задачу:


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

Разберем, что происходит в этом фрагменте:

  1. Функция НАЧАЛОПЕРИОДА(&ВыбДата, ДЕНЬ) превращает любую дату (например, "15.05.2023 14:30:15") в начало этих суток ("15.05.2023 00:00:00").
  2. Функция КОНЕЦПЕРИОДА(&ВыбДата, ДЕНЬ) превращает ту же дату в последний миг этих суток ("15.05.2023 23:59:59").
  3. Оператор МЕЖДУ включает обе границы, поэтому все документы, попавшие в этот диапазон (включая те, что созданы ровно в 00:00:00 и 23:59:59), попадут в выборку.

Способ 2. Подготовка параметров на стороне встроенного языка

С точки зрения чистоты кода и читаемости запроса, часто бывает удобнее вычислить границы периода заранее в коде 1С (BSL) и передать их в запрос уже готовыми значениями. Это упрощает текст самого запроса и делает отладку более наглядной.

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


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

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

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

Этот подход предпочтителен, когда вы планируете использовать одни и те же границы дат в нескольких разных запросах или если логика определения периода сложнее, чем просто "один день".

Важный нюанс: Оптимизация и использование индексов (SARGability)

При написании запросов к большим таблицам (где сотни тысяч или миллионы документов) критически важно, чтобы СУБД могла использовать индекс по полю Дата. Если индекс не используется, системе придется выполнять полное сканирование таблицы (Full Scan), что приведет к существенным тормозам.

Важное правило: Нельзя применять функции к индексированному полю в левой части условия ГДЕ.

Рассмотрим плохой пример:

ГДЕ НАЧАЛОПЕРИОДА(Реал.Дата, ДЕНЬ) = &ВыбДата — НЕПРАВИЛЬНО!

В этом случае СУБД сначала применит функцию к каждой строке в таблице, и только потом сравнит результат с параметром. Индекс по дате при этом "отключится".

Правильно: Всегда сравнивайте "чистое" поле документа с вычисленными границами, как мы делали в Способах 1 и 2. В этом случае индекс будет работать максимально эффективно.

Способ 3. Использование строгого сравнения (SQL-стиль)

Некоторые разработчики предпочитают использовать комбинацию >= и < вместо МЕЖДУ. Это гарантирует, что мы не захватим лишнюю секунду следующего дня в специфических случаях (хотя для 1С это редко актуально из-за точности в 1 секунду).

Логика выглядит следующим образом:


ГДЕ
    Реал.Дата >= &НачалоДня 
    И Реал.Дата < &НачалоСледующегоДня

Здесь &НачалоСледующегоДня — это ровно 00:00:00 следующей даты. Такой подход считается наиболее корректным с точки зрения теории баз данных.

Способ 4. Работа в Системе компоновки данных (СКД)

Если вы создаете отчет с помощью СКД, вам не обязательно вручную прописывать границы дня в коде. Платформа предоставляет удобные механизмы для работы с периодами.

Рассмотрим шаги по настройке в СКД:

  1. В схеме компоновки данных добавьте параметр Период с типом СтандартныйПериод.
  2. В настройках отчета пользователь сможет выбрать "Этот день", "Вчера" или конкретную дату через календарь.
  3. В тексте запроса используйте расширение языка запросов для СКД:
    
    ГДЕ
        Реал.Дата МЕЖДУ &ДатаНачала И &ДатаОкончания
    
  4. СКД автоматически подставит время 00:00:00 для &ДатаНачала и 23:59:59 для &ДатаОкончания.

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

Если ваша задача — получить данные не из самих документов, а из регистров (например, остатки или обороты), помните, что фильтрация по дате должна происходить в параметрах виртуальной таблицы, а не в секции ГДЕ.

Пример для регистра накопления:


ВЫБРАТЬ
    ПродажиОбороты.СуммаОборот
ИЗ
    РегистрНакопления.Продажи.Обороты(НАЧАЛОПЕРИОДА(&Дата, ДЕНЬ), КОНЕЦПЕРИОДА(&Дата, ДЕНЬ)) КАК ПродажиОбороты

В этом случае платформа 1С сама оптимизирует запрос к базе данных, обращаясь к предварительно рассчитанным итогам регистра, что работает в десятки раз быстрее, чем фильтрация через ГДЕ.

Заключение

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

← На главную