Как правильно передать дату в запрос 1С и почему не работает ДАТАВРЕМЯ с параметрами

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

При работе с языком запросов «1С:Предприятие 8» начинающие разработчики часто сталкиваются с проблемой: попытка передать дату в запрос через функцию ДАТАВРЕМЯ приводит к ошибке или к отсутствию данных в результате. В этой статье мы подробно разберем, почему конструкция ДАТАВРЕМЯ(&Параметр) является нежизнеспособной, как правильно оперировать датами в запросах и каким образом оптимизировать такие условия для повышения производительности системы.

Разбираем причину ошибки: Литералы против Параметров

Давайте проанализируем ситуацию, с которой столкнулся автор темы. Попытка написать в запросе ДАТАВРЕМЯ(&НачалоПериода) вызывает ошибку "Неверные параметры", хотя ручной ввод даты ДАТАВРЕМЯ(2021, 7, 1) работает корректно. Выясним причину этого поведения.

Функция ДАТАВРЕМЯ в языке запросов предназначена исключительно для создания литералов. Литерал — это константа, значение которой жестко прописано в тексте запроса на этапе его написания. Синтаксис этой функции строго определен: он принимает только целые числа (год, месяц, день, час, минута, секунда). Система ожидает увидеть там цифры, а не ссылку на переменную или параметр. Поэтому подставить туда &Параметр или результат другой функции невозможно.

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

Рассмотрим правильный пример кода на встроенном языке:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |   Набор.Ссылка КАК Ссылка
    |ИЗ
    |   Документ.НаправлениеНаИсследование КАК Набор
    |ГДЕ
    |   Набор.Дата >= &НачалоПериода";

// Передаем дату напрямую как параметр
Запрос.УстановитьПараметр("НачалоПериода", ТекущаяДата());
Результат = Запрос.Выполнить();

Проблема учета времени при сравнении дат

Проанализируем ситуацию дальше. Даже если запрос перестал выдавать ошибку, он может "не отрабатывать" (возвращать пустой результат). Почему так происходит? Посмотрим на логику сравнения. В 1С тип Дата всегда содержит время, вплоть до секунды.

Если мы пишем НАЧАЛОПЕРИОДА(Набор.Дата, ДЕНЬ) = &НачалоПериода и передаем в параметр ТекущаяДата(), которая, например, равна 17.08.2021 14:30:05, то сравнение всегда будет ложным. Функция НАЧАЛОПЕРИОДА сбросит время в поле базы данных в 00:00:00, а в параметре время останется текущим. Условие 00:00:00 = 14:30:05 никогда не выполнится.

Чтобы решить эту задачу, рассмотрим два основных подхода:

  1. Приведение параметра к началу дня в коде: Перед установкой параметра используйте функцию встроенного языка НачалоДня(). Запрос.УстановитьПараметр("НачалоПериода", НачалоДня(ТекущаяДата()));
  2. Приведение параметра внутри запроса: Используйте аналогичную функцию языка запросов. ГДЕ НАЧАЛОПЕРИОДА(Набор.Дата, ДЕНЬ) = НАЧАЛОПЕРИОДА(&НачалоПериода, ДЕНЬ)

Оптимизация производительности: SARGability

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

Рекомендуемый подход: Оставляйте поле даты "чистым", а все преобразования делайте над параметрами. Вместо того чтобы округлять дату документа до дня, лучше задать диапазон "от начала до конца дня" с помощью оператора МЕЖДУ.

Разберем пример эффективного условия:

ГДЕ Набор.Дата МЕЖДУ &НачалоДня И &КонецДня

В коде 1С подготовка параметров будет выглядеть так:


ВыбраннаяДата = ТекущаяДата();
Запрос.УстановитьПараметр("НачалоДня", НачалоДня(ВыбраннаяДата));
Запрос.УстановитьПараметр("КонецДня", КонецДня(ВыбраннаяДата));

Работа с периодом «Вчера и сегодня»

Рассмотрим вопрос из сообщения №20: как выбрать данные за два дня сразу? Ошибка часто заключается в использовании оператора И для разных дат. Логически поле не может быть одновременно равно двум разным значениям.

Правильно будет использовать диапазон или условие "больше или равно". Посмотрим, как это реализовать:

Вариант 1 (через МЕЖДУ):

ГДЕ Набор.Дата МЕЖДУ &НачалоВчера И &КонецСегодня

Где &НачалоВчера — это НачалоДня(ТекущаяДата() - 86400).

Вариант 2 (вычисление в запросе):

ГДЕ Набор.Дата >= ДОБАВИТЬКДАТЕ(&НачалоСегодня, ДЕНЬ, -1)

Почему "костыль" с форматом строки не работает?

В сообщении №17 автор пытался передать дату как строку через запятую: "2021,7,1". Это принципиальная ошибка. Язык запросов 1С строго типизирован. Если вы сравниваете поле типа Дата со значением типа Строка, система выдаст ошибку несовместимости типов или просто не найдет данных. Форматирование (функция Формат()) нужно только для визуального представления даты пользователю, но никогда не для передачи в условия запроса.

Подведем итоги

Проанализировав проблему, мы можем составить краткий чек-лист для работы с датами в запросах:

Следуя этим правилам, вы обеспечите не только корректность работы ваших отчетов и обработок, но и высокую скорость их выполнения даже при значительном росте объема данных в базе.

← На главную