Работа с запросами в 1С:Предприятие часто требует гибкости — особенно когда нужно передавать параметры, которые могут отсутствовать. Например, при формировании отчётов с фильтрами, где пользователь не всегда заполняет все поля. Необязательные параметры позволяют избежать ошибок и упрощают логику кода, но их реализация имеет нюансы в зависимости от версии платформы и контекста использования.
Многие разработчики сталкиваются с проблемой: как корректно обработать ситуацию, когда параметр не передан? Should we использовать ЗНАЧЕНИЕЗАПОЛНЕНО() или проверять на НЕ ОПРЕДЕЛЕНО? А как быть с типовыми запросами в управляемых формах, где параметры приходят из реквизитов? В этой статье разберём все способы — от базового синтаксиса до продвинутых техник с примерами кода и типичными ошибками.
Особое внимание уделим трем ключевым подходам:
- Использование
ЗНАЧЕНИЕЗАПОЛНЕНО()для проверки параметров. - Применение конструкции
ВЫБРАТЬ ... ГДЕ ... ИЛИ НЕ ЗНАЧЕНИЕЗАПОЛНЕНО(Параметр). - Динамическое формирование текста запроса с учетом наличия параметров.
Каждый метод имеет свои плюсы и минусы, которые зависят от задачи и версии 1С.
1. Базовый синтаксис: ЗНАЧЕНИЕЗАПОЛНЕНО()
Самый распространённый способ проверки необязательных параметров — функция ЗНАЧЕНИЕЗАПОЛНЕНО(). Она возвращает ИСТИНА, если параметр передан и не равен NULL (или НЕ ОПРЕДЕЛЕНО в новых версиях платформы). Этот метод подходит для большинства случаев, особенно когда параметры передаются из форм или других процедур.
Пример использования в запросе:
ВЫБРАТЬ
Товары.Наименование,
Товары.Артикул
ИЗ
Справочник.Товары КАК Товары
ГДЕ
(&ПараметрКатегория = ЗНАЧЕНИЕ(Справочник.КатегорииТоваров.ПустаяСсылка())
ИЛИ Товары.Категория = &ПараметрКатегория)
И (&ПараметрПоставщик = ЗНАЧЕНИЕ(Справочник.Поставщики.ПустаяСсылка())
ИЛИ Товары.ОсновнойПоставщик = &ПараметрПоставщик)
Обратите внимание на конструкцию ИЛИ — она позволяет игнорировать условие, если параметр не передан. Однако такой подход может усложнить чтение кода при большом количестве фильтров. Альтернатива — динамическое формирование текста запроса (разберём далее).
⚠️ Внимание: В платформе 1С:Предприятие 8.3.20+ появилось ключевое словоНЕ ОПРЕДЕЛЕНО, которое более корректно обрабатывает неинициализированные параметры. Для старых версий используйтеЗНАЧЕНИЕЗАПОЛНЕНО().
- ✅ Простота реализации — не требует сложной логики.
- ✅ Совместимость со всеми версиями платформы.
- ❌ Может снижать производительность при большом количестве параметров.
- ❌ Код становится громоздким, если фильтров больше 3-4.
2. Динамическое формирование текста запроса
Если параметров много или они часто меняются, целесообразно формировать текст запроса динамически — добавляя условия только для тех параметров, которые переданы. Этот подход требует больше кода, но делает запрос более читаемым и производительным.
Пример реализации:
ТекстЗапроса = "
|ВЫБРАТЬ
| Товары.Наименование,
| Товары.Артикул
|ИЗ
| Справочник.Товары КАК Товары
|ГДЕ
| 1 = 1";
// Добавляем условия только для заполненных параметров
Если ЗНАЧЕНИЕЗАПОЛНЕНО(ПараметрКатегория) Тогда
ТекстЗапроса = ТекстЗапроса + "
| И Товары.Категория = &ПараметрКатегория";
КонецЕсли;
Если ЗНАЧЕНИЕЗАПОЛНЕНО(ПараметрПоставщик) Тогда
ТекстЗапроса = ТекстЗапроса + "
| И Товары.ОсновнойПоставщик = &ПараметрПоставщик";
КонецЕсли;
Запрос = Новый Запрос(ТекстЗапроса);
Запрос.УстановитьПараметр("ПараметрКатегория", ПараметрКатегория);
Запрос.УстановитьПараметр("ПараметрПоставщик", ПараметрПоставщик);
Такой подход особенно полезен для сложных отчётов, где фильтры задаются пользователем через форму. Однако здесь важно следить за синтаксической корректностью — например, не забывать про оператор И перед каждым новым условием.
Используйте символьную метку 1 = 1 в начале условия ГДЕ, чтобы упростить добавление динамических фильтров. Это избавит от необходимости проверять, нужно ли ставить первое И.
| Способ | Плюсы | Минусы | Когда использовать |
|---|---|---|---|
ЗНАЧЕНИЕЗАПОЛНЕНО() в условии |
Простота, совместимость | Громоздкий код при многих параметрах | Простые запросы с 1-3 фильтрами |
| Динамический текст | Читаемость, производительность | Больше кода, риск синтаксических ошибок | Сложные отчёты с множеством фильтров |
НЕ ОПРЕДЕЛЕНО (8.3.20+) |
Более корректная проверка | Не работает в старых версиях | Новые проекты на актуальных платформах |
3. Использование НЕ ОПРЕДЕЛЕНО в новых версиях 1С
Начиная с версии 1С:Предприятие 8.3.20, появилась возможность проверять параметры на НЕ ОПРЕДЕЛЕНО. Это более надёжный способ, чем ЗНАЧЕНИЕЗАПОЛНЕНО(), так как он корректно обрабатывает случаи, когда параметр не просто пуст, а вообще не инициализирован.
Пример кода:
Если НЕ ОПРЕДЕЛЕНО(ПараметрКатегория) Тогда
ПараметрКатегория = НеопределённоеЗначение;
КонецЕсли;
Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| Товары.Наименование
|ИЗ
| Справочник.Товары КАК Товары
|ГДЕ
| (&ПараметрКатегория = ЗНАЧЕНИЕ(Справочник.КатегорииТоваров.ПустаяСсылка())
| ИЛИ Товары.Категория = &ПараметрКатегория)";
Важно: НЕ ОПРЕДЕЛЕНО работает только с переменными, объявленными через Перем или в модулях объектов. Для параметров процедур/функций используйте ЗНАЧЕНИЕЗАПОЛНЕНО().
⚠️ Внимание: При использованииНЕ ОПРЕДЕЛЕНОв управляемых формах убедитесь, что параметры передаются черезПараметрыВыполнениякорректно. В некоторых случаях неинициализированные параметры могут приводить к ошибкам при компиляции запроса.
4. Обработка необязательных параметров в управляемых формах
В управляемых формах параметры часто приходят из реквизитов или полей ввода. Здесь важно учитывать, что пустое значение поля не всегда эквивалентно НЕ ОПРЕДЕЛЕНО. Например, поле типа СправочникСсылка может содержать пустую ссылку, а не NULL.
Пример обработки параметров из формы:
Процедура СформироватьОтчёт(Команда)
Запрос = Новый Запрос;
// Получаем значения из формы
ПараметрДаты = ЭлементыФормы.Период.Значение;
ПараметрКонтрагент = ЭлементыФормы.Контрагент.Значение;
// Проверяем заполненность
Если НЕ ЗначениеЗаполнено(ПараметрДаты.Начало) Тогда
ПараметрДаты.Начало = НачалоДня(ТекущаяДата() - 365);
КонецЕсли;
ТекстЗапроса = "
|ВЫБРАТЬ
| Документ.Дата,
| Документ.Сумма
|ИЗ
| Документ.РеализацияТоваровУслуг КАК Документ
|ГДЕ
| Документ.Дата >= &НачалоПериода
| " + ?(ЗначениеЗаполнено(ПараметрКонтрагент), "
| И Документ.Контрагент = &Контрагент", "");
Запрос.Текст = ТекстЗапроса;
Запрос.УстановитьПараметр("НачалоПериода", ПараметрДаты.Начало);
Если ЗначениеЗаполнено(ПараметрКонтрагент) Тогда
Запрос.УстановитьПараметр("Контрагент", ПараметрКонтрагент);
КонецЕсли;
Результат = Запрос.Выполнить();
КонецПроцедуры
В этом примере используется тернарный оператор ?(Условие, Значение1, Значение2) для динамического добавления условия по контрагенту. Такой подход сокращает код и делает его более лаконичным.
Получить значения из элементов формы|Проверить на ЗначениеЗаполнено()|Инициализировать параметры по умолчанию|Добавить условия в запрос динамически|Установить параметры перед выполнением-->
5. Типичные ошибки и как их избежать
При работе с необязательными параметрами разработчики часто допускают ошибки, которые приводят к некорректным результатам или падению производительности. Рассмотрим наиболее распространённые из них:
- 🚫 Игнорирование типа параметра: Если параметр имеет тип
СправочникСсылка, а в запросе сравнивается сNULL, может возникнуть ошибка. Всегда используйтеЗНАЧЕНИЕ(Справочник.Имя.ПустаяСсылка())для сравнения. - 🚫 Избыточные проверки: Не нужно проверять параметр на заполненность несколько раз. Достаточно одной проверки перед формированием запроса.
- 🚫 Неучтённые NULL в результатах: Если параметр может быть
NULL, но в запросе используется в вычислениях (например, вВЫБОР КОГДА), добавьте обработку черезЕСТЬNULL(). - 🚫 Забытые УстановитьПараметр(): Динамически добавленное условие требует установки параметра, иначе запрос упадёт с ошибкой.
Пример ошибки и её исправления:
// ОШИБКА: Сравнение со ссылкой без проверки на NULL
ГДЕ Товары.Категория = &ПараметрКатегория
// ПРАВИЛЬНО:
ГДЕ (&ПараметрКатегория = ЗНАЧЕНИЕ(Справочник.КатегорииТоваров.ПустаяСсылка())
ИЛИ Товары.Категория = &ПараметрКатегория)
Что будет, если не обработать необязательный параметр?
Если параметр не обработан, а в запросе используется условие вида ГДЕ Поле = &Параметр, то при отсутствии параметра 1С выдаст ошибку "Неопределённое значение параметра запроса". В лучшем случае запрос вернёт пустой результат, в худшем — прервёт выполнение с исключением.
6. Продвинутые техники: параметры по умолчанию и кэширование
Для оптимизации работы с необязательными параметрами можно использовать значения по умолчанию и кэширование запросов. Например, если параметр не передан, подставлять стандартное значение (текущая дата, пустая ссылка, нулевое число).
Пример с кэшированием:
Процедура ПолучитьДанные(ПараметрКатегория = Неопределено, ПараметрДаты = Неопределено)
// Устанавливаем значения по умолчанию
Если НЕ ЗначениеЗаполнено(ПараметрДаты) Тогда
ПараметрДаты = ТекущаяДата();
КонецЕсли;
КлючКэша = "ЗапросТоваров_" +
?(ЗначениеЗаполнено(ПараметрКатегория), ПараметрКатегория.УникальныйИдентификатор(), "ВсеКатегории") + "_" +
Формат(ПараметрДаты, "ДФ=yyyyMMdd");
// Проверяем кэш
Если Кэш.СуществуетКлюч(КлючКэша) Тогда
Возврат Кэш.Получить(КлючКэша);
КонецЕсли;
// Формируем и выполняем запрос
Запрос = Новый Запрос;
Запрос.Текст = "
|ВЫБРАТЬ
| Товары.Наименование
|ИЗ
| Справочник.Товары КАК Товары
|ГДЕ
| Товары.ДатаПоступления <= &МаксимальнаяДата
| " + ?(ЗначениеЗаполнено(ПараметрКатегория), "
| И Товары.Категория = &Категория", "");
Запрос.УстановитьПараметр("МаксимальнаяДата", КонецДня(ПараметрДаты));
Если ЗначениеЗаполнено(ПараметрКатегория) Тогда
Запрос.УстановитьПараметр("Категория", ПараметрКатегория);
КонецЕсли;
Результат = Запрос.Выполнить();
Кэш.Добавить(КлючКэша, Результат);
Возврат Результат;
КонецПроцедуры
Такой подход сокращает количество повторных выполнений одинаковых запросов, что особенно актуально для веб-сервисов или фоновых задач.
Использование значений по умолчанию и кэширования запросов с необязательными параметрами может увеличить производительность системы на 30-50% при частых повторных обращениях.
7. Сравнение подходов: какой выбрать?
Выбор метода обработки необязательных параметров зависит от нескольких факторов:
- 📌 Сложность запроса: Для простых запросов с 1-2 параметрами подойдёт
ЗНАЧЕНИЕЗАПОЛНЕНО(). Для сложных — динамическое формирование. - 📌 Версия платформы: В 1С 8.3.20+ предпочтительнее
НЕ ОПРЕДЕЛЕНО. - 📌 Источник параметров: В управляемых формах удобнее динамический текст, в отчётах — комбинированный подход.
- 📌 Производительность: Динамические запросы быстрее, но требуют больше кода.
Рекомендации по выбору:
| Критерий | ЗНАЧЕНИЕЗАПОЛНЕНО() | Динамический текст | НЕ ОПРЕДЕЛЕНО |
|---|---|---|---|
| Простота кода | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
| Производительность | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Совместимость | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ (только 8.3.20+) |
⚠️ Внимание: В некоторых конфигурациях (например, 1С:ERP или 1С:УТ 11) стандартные отчёты уже содержат механизмы обработки необязательных параметров. Перед изменением кода проверьте, не переопределяете ли вы существующую логику.
FAQ: Частые вопросы по необязательным параметрам в 1С
Как передать необязательный параметр в запрос из управляемой формы?
Используйте свойство Значение элемента формы и проверяйте его на заполненность через ЗначениеЗаполнено(). Пример:
Параметр = ЭлементыФормы.ПолеВвода.Значение;
Если НЕ ЗначениеЗаполнено(Параметр) Тогда
Параметр = Неопределено; // или значение по умолчанию
КонецЕсли;
Почему запрос падает с ошибкой "Неопределённое значение параметра", если я использовал ЗНАЧЕНИЕЗАПОЛНЕНО()?
Ошибка возникает, если вы добавили условие с параметром в текст запроса, но не установили его через УстановитьПараметр(). Например:
ТекстЗапроса = "ГДЕ Поле = &Параметр";
Запрос.Текст = ТекстЗапроса;
// Забыли установить параметр!
// Запрос.УстановитьПараметр("Параметр", Значение);
Всегда проверяйте, что все параметры в тексте запроса установлены перед выполнением.
Можно ли использовать необязательные параметры в пакетных запросах?
Да, но нужно учитывать, что параметры в пакетных запросах устанавливаются для всех запросов в пакете. Пример:
Запрос1 = Новый Запрос("ВЫБРАТЬ 1 ГДЕ 1 = &Флаг");
Запрос2 = Новый Запрос("ВЫБРАТЬ 2 ГДЕ 2 = &Флаг");
Пакет = Новый ПакетЗапросов;
Пакет.Добавить(Запрос1);
Пакет.Добавить(Запрос2);
Пакет.УстановитьПараметр("Флаг", Истина);
Результат = Пакет.Выполнить();
Если параметр необязательный, установите его значение по умолчанию перед добавлением в пакет.
Как обработать необязательный параметр типа "Массив"?
Для массивов используйте проверку ЗначениеЗаполнено() и функцию В() в запросе:
Если НЕ ЗначениеЗаполнено(МассивИД) Тогда
МассивИД = Новый Массив(); // или массив с одним элементом по умолчанию
КонецЕсли;
Запрос.Текст = "
|ВЫБРАТЬ
| Элементы.Наименование
|ИЗ
| Справочник.Элементы КАК Элементы
|ГДЕ
| " + ?(МассивИД.Количество() > 0, "
| Элементы.Ссылка В (&МассивИД)", "
| 1 = 1");
Влияют ли необязательные параметры на производительность запросов?
Да, но влияние зависит от подхода:
ЗНАЧЕНИЕЗАПОЛНЕНО()в условиях может замедлить запрос, так как 1С проверяет каждое условие.- Динамический текст запроса обычно быстрее, так как содержит только актуальные условия.
- Использование
НЕ ОПРЕДЕЛЕНОне влияет на производительность напрямую, но упрощает код.
Для критичных по скорости запросов тестируйте оба подхода и сравнивайте планы выполнения.