Как найти документ по дате в 1С, если поиск не выдает результат из-за времени?

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

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

Почему обычное сравнение дат не работает?

В системе 1С тип данных Дата всегда содержит и календарную дату, и время (часы, минуты, секунды). Если вы вводите дату в поле поиска (например, "01.09.2023"), система по умолчанию подставляет время 00:00:00. В то же время реальные документы в базе данных записываются с конкретным временем (например, "01.09.2023 14:30:15").

При использовании оператора "равно" (=) СУБД ищет полное совпадение. Следовательно, документ, созданный в середине дня, не будет равен дате с нулевым временем. Наша задача — научить запрос игнорировать время и искать все документы внутри заданных суток.

Решение 1: Использование оператора МЕЖДУ (Рекомендуемый вариант)

Самый простой и правильный с точки зрения производительности способ — это поиск документов в интервале от начала нужного дня до его конца. Рассмотрим пример кода, который решает проблему:


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

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

Анализ производительности и типичные ошибки

Проанализируем ситуацию, которая часто встречается в советах на форумах: использование функций прямо внутри текста запроса. Рассмотрим пример, как делать не рекомендуется:


// ПЛОХОЙ ПРИМЕР (НИЗКАЯ СКОРОСТЬ)
|ГДЕ
|    НАЧАЛОПЕРИОДА(РеализацияТоваровУслуг.Дата, ДЕНЬ) = &ДатаПоиска

Выясним причину, почему это плохо: Если мы применяем функцию НАЧАЛОПЕРИОДА к полю Дата в левой части условия, СУБД не сможет использовать индекс по этому полю. Системе придется прочитать каждую запись в таблице, вычислить для нее начало дня и только потом сравнить. На больших базах это приведет к значительным задержкам. Использование оператора МЕЖДУ (или сравнения через больше/меньше) позволяет СУБД выполнить поиск по индексу (Index Seek), что в десятки раз быстрее.

Решение 2: Строгое сравнение с началом следующего дня

Существует еще более строгий подход, который исключает любые проблемы с точностью до секунды. Мы можем искать документы, которые больше или равны началу искомого дня, но строго меньше начала следующего дня.


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

Запрос.УстановитьПараметр("НачалоДня", НачалоДня(ДатаПоиска));
// Добавляем 1 день (86400 секунд) и берем его начало
Запрос.УстановитьПараметр("НачалоСледующегоДня", НачалоДня(ДатаПоиска + 86400));

Этот метод считается максимально корректным, так как он покрывает абсолютно весь временной диапазон суток, включая возможные микросекунды, если данные были загружены из внешних систем напрямую в SQL.

Важные нюансы использования объекта Граница

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

Итоги

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

  1. Никогда не используйте прямое равенство Дата = &Дата, если не уверены, что время документа всегда равно 00:00:00.
  2. Используйте оператор МЕЖДУ или связку >= и <=.
  3. Передавайте в параметры готовые значения, вычисленные функциями НачалоДня() и КонецДня() на языке 1С, а не в самом запросе.
  4. Избегайте функций 1С (таких как НАЧАЛОПЕРИОДА) над полями таблиц в условиях запроса для сохранения высокой скорости работы.

Рассмотренные методы позволят вам создавать надежные и быстрые механизмы поиска документов в любых конфигурациях на платформе 1С:Предприятие 8.

← На главную