При разработке сложных отчетов или обработок в системе 1С:Предприятие 8 программисты часто сталкиваются с необходимостью вычисления сроков (например, даты износа спецодежды или срока годности товара) прямо в тексте запроса. Функция ДОБАВИТЬКДАТЕ кажется идеальным инструментом для этих целей, однако она имеет ряд скрытых ограничений, которые могут привести к ошибке «Неверные параметры». В данной статье мы детально проанализируем, почему возникает эта ошибка, и разберем правильные подходы к написанию запроса.
Рассмотрим ситуацию, с которой столкнулся автор темы. В запросе требовалось рассчитать дату износа, прибавляя количество месяцев к дате передачи. Если основной срок не задан, должен был использоваться альтернативный срок из свойств номенклатуры.
Первая и самая распространенная ошибка — использование операторов сравнения = или <> при работе с NULL. В языке запросов 1С (как и в стандарте SQL) любое сравнение с NULL через обычное равенство всегда возвращает результат «Ложь». Рассмотрим фрагмент ошибочного кода:
ВЫБОР
КОГДА ВТ_План.СрокНоски <> NULL Тогда
ДОБАВИТЬКДАТЕ(ВТ_Факт.ДатаПередачи, МЕСЯЦ, ВТ_План.СрокНоски)
КОГДА ВТ_План.СрокНоски = NULL Тогда
ДОБАВИТЬКДАТЕ(ВТ_Факт.ДатаПередачи, МЕСЯЦ, ВТ_Факт.СрокСвойства)
КОНЕЦ КАК ДатаИзноса
Для исправления этой логической ошибки обязательно следует использовать специальные операторы ЕСТЬ NULL или НЕ ... ЕСТЬ NULL. Однако, даже после исправления синтаксиса условий, запрос может продолжать выдавать ошибку параметров в самой функции ДОБАВИТЬКДАТЕ.
Функция ДОБАВИТЬКДАТЕ(Дата, ТипУвеличения, Количество) очень требовательна к своим аргументам. Основная сложность заключается в третьем параметре — Количество. Проанализируем технические нюансы:
СрокСвойства хранятся дробные значения, СУБД (особенно PostgreSQL) может отвергнуть запрос.&Период) в качестве третьего аргумента. Использование полей таблиц стало возможным, но требует «подсказки» для оптимизатора.Как выяснилось в ходе обсуждения, самым надежным способом заставить ДОБАВИТЬКДАТЕ работать с полями временных таблиц является использование функции ВЫРАЗИТЬ. Это позволяет жестко типизировать значение перед его передачей в функцию расчета даты.
Разберем исправленный вариант кода:
ВЫБРАТЬ
ВТ_Факт.Подразделение,
ВТ_Факт.ДатаПередачи,
ВЫБОР
КОГДА ВТ_План.СрокНоски ЕСТЬ NULL
ТОГДА ДОБАВИТЬКДАТЕ(ВТ_Факт.ДатаПередачи, МЕСЯЦ, ВЫРАЗИТЬ(ВТ_Факт.СрокСвойства КАК ЧИСЛО(10, 0)))
ИНАЧЕ ДОБАВИТЬКДАТЕ(ВТ_Факт.ДатаПередачи, МЕСЯЦ, ВЫРАЗИТЬ(ВТ_План.СрокНоски КАК ЧИСЛО(10, 0)))
КОНЕЦ КАК ДатаИзноса
ИЗ
ВТ_Факт КАК ВТ_Факт
ЛЕВОЕ СОЕДИНЕНИЕ ВТ_План КАК ВТ_План ПО ВТ_Факт.Номенклатура = ВТ_План.Номенклатура
В данном примере мы используем ВЫРАЗИТЬ(Поле КАК ЧИСЛО(10, 0)). Указание точности «0» гарантирует системе, что мы передаем целое число, что критически важно для SQL-функций работы с датами.
Чтобы сделать код более читаемым и избежать громоздких конструкций ВЫБОР...КОГДА...КОНЕЦ, мы можем использовать функцию ЕСТЬNULL. Она позволяет подставить значение по умолчанию (например, 0), если поле в таблице не заполнено.
Проанализируем более элегантный способ решения задачи:
ВЫБРАТЬ
ВТ_Факт.ДатаПередачи,
ДОБАВИТЬКДАТЕ(
ВТ_Факт.ДатаПередачи,
МЕСЯЦ,
ВЫРАЗИТЬ(ЕСТЬNULL(ВТ_План.СрокНоски, ЕСТЬNULL(ВТ_Факт.СрокСвойства, 0)) КАК ЧИСЛО(10, 0))
) КАК ДатаИзноса
ИЗ
ВТ_Факт КАК ВТ_Факт
Важное примечание: Если в функцию ДОБАВИТЬКДАТЕ попадет NULL (например, если оба срока не заполнены и мы не использовали ЕСТЬNULL), то результатом всей функции также будет NULL. Это не вызовет ошибку исполнения, но может привести к пустым значениям в отчете.
Поведение функции может отличаться в зависимости от используемой серверной среды. Выясним причины этих различий:
MS SQL Server: Обычно более лоялен к типам данных и автоматически выполняет неявное приведение типов (Implicit Conversion). Поэтому на файловых базах или MS SQL ошибка может не проявляться долгое время.
PostgreSQL: Строго следит за соответствием типов. Попытка передать тип numeric туда, где ожидается integer, приведет к ошибке на уровне SQL-движка. Именно поэтому явное ВЫРАЗИТЬ(... КАК ЧИСЛО(10, 0)) является «золотым стандартом» кроссплатформенной разработки на 1С.
Версия 8.3.18 и выше: В современных версиях платформы механизмы трансляции запросов стали более интеллектуальными, однако ограничения на типизацию полей во временных таблицах (особенно если они получены в результате сложных соединений) сохраняются.
Для стабильной работы ваших запросов при использовании функции ДОБАВИТЬКДАТЕ рекомендуем придерживаться следующих правил:
NULL с помощью функции ЕСТЬNULL или оператора ЕСТЬ NULL.ВЫРАЗИТЬ с указанием нулевой точности.Соблюдение этих простых правил позволит вам избежать трудноуловимых ошибок «Неверные параметры» и обеспечит корректную работу ваших программ на любых СУБД.