Как исправить ошибку «Не задано значение параметра» в запросе 1С

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

При разработке отчетов и обработок в среде «1С:Предприятие 8» начинающие разработчики часто сталкиваются с исключением во время выполнения метода Выполнить() объекта Запрос: «Не задано значение параметра». Выясним причину этой ошибки, рассмотрим типовые заблуждения при работе с параметрами запросов и разберем по шагам, как правильно передавать параметры, работать с иерархией подразделений и оптимизировать код.

Причина возникновения ошибки

В тексте запроса символ амперсанда (&) обозначает параметр, значение которого платформа ожидает получить до момента исполнения SQL-запроса на сервере базы данных. Если в секциях ГДЕ, ВЫБОР или в параметрах виртуальных таблиц объявлен параметр, например &ТекущееПодразделение, платформа 1С требует явного присвоения ему значения с помощью метода УстановитьПараметр().

Если разработчик забывает инициализировать хотя бы один параметр или допускает опечатку в его имени, метод Запрос.Выполнить() аварийно прерывает выполнение программы с ошибкой времени исполнения.

Типичные ошибки при передаче параметров

Проанализируем распространенные заблуждения, возникающие при инициализации параметров:

  1. Путаница между полями выборки и параметрами. Объявление поля в секции ВЫБРАТЬ с помощью псевдонима КАК ТекущееПодразделение формирует колонку в результирующей таблице, но никак не заполняет условие фильтрации &ТекущееПодразделение в секции ГДЕ. Параметр фильтрации всегда должен заполняться из внешней переменной.
  2. Передача неинициализированной переменной. При попытке вызвать Запрос1.УстановитьПараметр("ТекущееПодразделение", ТекущееПодразделение) компилятор сообщает: Переменная не определена (ТекущееПодразделение), если переменная с таким именем не была объявлена или не является реквизитом формы/отчета.
  3. Передача менеджера вместо ссылки. Ошибочная конструкция Справочники.ПодразделенияОрганизаций возвращает объект СправочникМенеджер, а не конкретный элемент данных. В параметр фильтра необходимо передавать значение типа СправочникСсылка или массив ссылок.

Пошаговое решение: правильная установка параметров

Разберем по шагам, как корректно передать подразделение и другие параметры в объект Запрос перед его выполнением. Все параметры должны быть определены строго до вызова метода Выполнить().

Посмотрим на пример правильного заполнения параметров:


// 1. Получаем ссылку на подразделение из реквизита отчета или формы
ПодразделениеОтбора = Отчет.Подразделение; // СправочникСсылка.ПодразделенияОрганизаций

// 2. Создаем и настраиваем запрос
Запрос1 = Новый Запрос;
Запрос1.Текст = 
    "ВЫБРАТЬ
    |	ТекущиеКадровыеДанные.ТекущееПодразделение КАК Подразделение,
    |	ТекущиеКадровыеДанные.Сотрудник КАК Сотрудник
    |ИЗ
    |	РегистрСведений.ТекущиеКадровыеДанныеСотрудников КАК ТекущиеКадровыеДанные
    |ГДЕ
    |	ТекущиеКадровыеДанные.ТекущееПодразделение В ИЕРАРХИИ(&ТекущееПодразделение)
    |	И ТекущиеКадровыеДанные.ТекущееСостояние <> &Состояние";

// 3. Устанавливаем ВСЕ параметры, объявленные в тексте запроса
Запрос1.УстановитьПараметр("ТекущееПодразделение", ПодразделениеОтбора);
Запрос1.УстановитьПараметр("Состояние", Перечисления.СостоянияСотрудника.Увольнение);

// 4. Выполняем запрос
РезультатЗапроса = Запрос1.Выполнить();
Выборка = РезультатЗапроса.Выбрать();

Программная проверка параметров запроса

Чтобы исключить падение системы из-за забытых параметров, рассмотрим полезный встроенный инструмент платформы. У объекта Запрос доступен метод НайтиПараметры(). Он возвращает коллекцию описаний всех параметров, встретившихся в тексте запроса. С его помощью можно программно проверить, все ли параметры были заданы разработчиком:


НайденныеПараметры = Запрос1.НайтиПараметры();
Для Каждого ОписаниеПараметра Из НайденныеПараметры Цикл
    Если Не Запрос1.Параметры.Свойство(ОписаниеПараметра.Имя) Тогда
        ВызватьИсключение "Не заполнен обязательный параметр запроса: " + ОписаниеПараметра.Имя;
    КонецЕсли;
КонецЦикла;

Оптимизация работы с иерархией подразделений

В исходных текстах начинающих разработчиков часто встречается проверка иерархии через обращение к родителям:


// Антипаттерн: избыточные левые соединения и жесткое ограничение уровней
ГДЕ
    ТекущиеКадровыеДанные.ТекущееПодразделение = &ТекущееПодразделение
    ИЛИ ТекущиеКадровыеДанные.ТекущееПодразделение.Родитель = &ТекущееПодразделение
    ИЛИ ТекущиеКадровыеДанные.ТекущееПодразделение.Родитель.Родитель = &ТекущееПодразделение

Каждое обращение через точку к реквизиту Родитель порождает неявное соединение (LEFT JOIN) в итоговом SQL-запросе, что существенно снижает скорость работы отчета и не позволяет учитывать подразделения с большей вложенностью.

Для проверки принадлежности элемента ветке иерархии любой глубины используем специальную конструкцию 1С: В ИЕРАРХИИ:


ГДЕ
    ТекущиеКадровыеДанные.ТекущееПодразделение В ИЕРАРХИИ (&ТекущееПодразделение)

Если же отчет строится без фильтрации по конкретному подразделению (по всей организации), условие отбора следует полностью исключить из текста запроса либо формировать текст динамически.

Оптимизация обработки результатов выборки

Проанализируем распространенную ошибку производительности при обходе выборки результата запроса:


// Антипаттерн: поиск ссылки в цикле по каждой строке
Пока Выборка.Следующий() Цикл
    Если Выборка.Категория = Справочники.КВ_КатегорииСотрудников.НайтиПоКоду("000000001") Тогда
        // обработка данных
    КонецЕсли;
КонецЦикла;

Вызов метода НайтиПоКоду() внутри цикла выполняет отдельный запрос к базе данных на каждую запись выборки. Если в выборке тысячи строк, формирование отчета катастрофически замедлится.

Для исправления ситуации воспользуемся одним из следующих подходов:

  1. Перенос условия в текст запроса: передать эталонную категорию в запрос через параметр и отфильтровать данные средствами СУБД.
  2. Кэширование ссылки до начала цикла: найти ссылку один раз в переменную перед обходом выборки:
    
    КатегорияЭталон = Справочники.КВ_КатегорииСотрудников.НайтиПоКоду("000000001");
    Пока Выборка.Следующий() Цикл
        Если Выборка.Категория = КатегорияЭталон Тогда
            // обработка данных без лишних обращений к базе
        КонецЕсли;
    КонецЦикла;
    

Рекомендация: переход на Систему компоновки данных (СКД)

Ручное создание отчетов через объект ТаблицаЗначений, написание циклов выгрузки и ручная привязка параметров в современных версиях «1С:Предприятие 8» являются устаревшим подходом. Для построения списков численности сотрудников и кадровых отчетов рекомендуется использовать Систему компоновки данных (СКД).

Преимущества использования СКД:

  1. Автоматическое создание пользовательского интерфейса с полями выбора параметров (период, подразделение, организация).
  2. Автоматическая обработка иерархических отборов вида «В группе» или «В иерархии».
  3. Если пользователь не указал подразделение в настройках, СКД автоматически убирает соответствующее условие из итогового запроса, избавляя разработчика от ручного контроля незаполненных параметров.
← На главную