При построении аналитических отчетов и разработке механизмов сравнения показателей часто возникает необходимость выбрать данные не только за текущий момент, но и за аналогичный период прошлого года. В системе 1С:Предприятие для этих целей существует мощный механизм работы с датами непосредственно в тексте запроса. Разберем по шагам, как правильно использовать эти функции, каких ошибок стоит избегать и как система ведет себя в нестандартных ситуациях, таких как високосный год.
Для того чтобы получить дату, смещенную на определенный интервал (день, месяц, квартал или год), в языке запросов 1С предусмотрена специализированная функция ДОБАВИТЬКДАТЕ. Рассмотрим ситуацию, когда нам нужно найти документы, дата которых строго равна выбранной пользователем дате минус один год.
Синтаксис функции выглядит следующим образом: ДОБАВИТЬКДАТЕ(ИсходнаяДата, ТипУвеличения, Величина). Проанализируем пример кода, который решает задачу получения документов за прошлый год:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка КАК Ссылка,
РеализацияТоваровУслуг.Дата КАК Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
РеализацияТоваровУслуг.Дата = ДОБАВИТЬКДАТЕ(&ДатаПараметр, ГОД, -1)
В данном примере мы передаем в запрос параметр &ДатаПараметр. Система берет это значение, вычитает из него один год и сравнивает результат с полем Дата в базе данных. Обратите внимание, что ключевое слово ГОД пишется без кавычек — это предопределенное значение языка запросов.
Часто начинающие разработчики сталкиваются с ошибкой "Поле не найдено: ГОД". Выясним причину этой проблемы. Как правило, она возникает в двух случаях:
ГОД, так как это не строка, а литерал типа периода.ДОБАВИТЬКДАТЕ шли ровно три параметра, разделенные запятыми.Если задача стоит шире — получить данные сразу за две конкретные даты (например, за 01.01.2014 и 01.01.2013), — нам потребуется использовать оператор В или логическое ИЛИ. Рассмотрим, как это реализовать наиболее эффективно:
ВЫБРАТЬ
РеализацияТоваровУслуг.Ссылка КАК Ссылка,
РеализацияТоваровУслуг.Дата КАК Дата
ИЗ
Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
ГДЕ
РеализацияТоваровУслуг.Дата В (&Дата, ДОБАВИТЬКДАТЕ(&Дата, ГОД, -1))
В этом случае запрос вернет записи, соответствующие обеим точкам во времени. Если же нам нужен интервал времени (весь год), мы используем оператор МЕЖДУ:
ГДЕ
РеализацияТоваровУслуг.Дата МЕЖДУ ДОБАВИТЬКДАТЕ(&Дата, ГОД, -1) И &Дата
Проанализируем ситуацию, которая часто ставит в тупик: что произойдет, если мы вычтем один год из даты 29 февраля 2024 года? В обычном (невисокосном) году такой даты не существует.
Платформа 1С обрабатывает это следующим образом: при добавлении или вычитании лет, если результат попадает на несуществующий день (29 февраля), система автоматически возвращает 28 февраля. Это важное поведение, которое стоит учитывать при расчете графиков платежей или аналитики, так как переход на 1 марта (как предполагают некоторые) в 1С не происходит. Рассмотрим пример:
Если &Дата = 29.02.2024, то ДОБАВИТЬКДАТЕ(&Дата, ГОД, -1) вернет 28.02.2023.
Важным аспектом профессиональной разработки является скорость выполнения запроса. Существует правило: нельзя применять функции к полям таблиц в условии ГДЕ, если вы хотите, чтобы СУБД использовала индексы.
Сравним два варианта:
Плохой вариант (медленно):
ГДЕ ДОБАВИТЬКДАТЕ(Реализация.Дата, ГОД, 1) = &НужнаяДата
В этом случае СУБД будет вынуждена вычислить функцию для каждой строки таблицы (Full Table Scan), прежде чем сравнить ее с параметром. Индекс по полю Дата работать не будет.
Хороший вариант (быстро):
ГДЕ Реализация.Дата = ДОБАВИТЬКДАТЕ(&НужнаяДата, ГОД, -1)
Здесь функция применяется к константе (параметру), вычисляется один раз, и СУБД мгновенно находит нужные записи по индексу.
Помимо сложения и вычитания, часто требуется вычислить разницу между двумя событиями. Для этого используется функция РАЗНОСТЬДАТ(Дата1, Дата2, Тип).
Важно помнить, что РАЗНОСТЬДАТ возвращает количество пройденных "границ" периодов. Например, разница в годах между 31 декабря и 1 января следующего года будет равна 1, хотя фактически прошел один день. Это поведение полезно для быстрого определения, наступил ли следующий календарный период.
Функции работы с датами поддерживают следующие типы периодов:
СЕКУНДАМИНУТАЧАСДЕНЬНЕДЕЛЯМЕСЯЦКВАРТАЛГОДПри выполнении арифметических операций с датами в запросах следует проявлять осторожность с незаполненными значениями. В 1С "пустая" дата соответствует 01.01.0001 00:00:00. Если вы попытаетесь вычесть из этой даты год, на уровне некоторых СУБД (например, Microsoft SQL Server) возникнет критическая ошибка, так как дата выйдет за пределы допустимого диапазона (ниже 1753 года в некоторых версиях или просто в область отрицательных значений).
Посмотрим, как обезопасить свой код:
ГДЕ
РеализацияТоваровУслуг.Дата <> ДАТАВРЕМЯ(1, 1, 1)
И РеализацияТоваровУслуг.Дата = ДОБАВИТЬКДАТЕ(&Дата, ГОД, -1)
Такая проверка гарантирует стабильность работы системы даже при наличии в базе документов с незаполненной датой.
Подводя итог, можно сказать, что работа с датами в запросах 1С требует понимания механизмов трансляции кода 1С в SQL-запросы. Основным инструментом является функция ДОБАВИТЬКДАТЕ, которая корректно обрабатывает календарные нюансы. При работе с ней всегда старайтесь применять преобразования к параметрам, а не к полям таблиц, чтобы сохранять высокую производительность системы. Если же вам нужно анализировать динамику за разные годы, наиболее эффективным методом будет передача списка дат в качестве массива параметров или использование нескольких условий, объединенных логикой ИЛИ.