Почему возникает ошибка «Недопустимое значение параметра» при отборе в регистре бухгалтерии 1С и как её исправить?

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

При работе с регистрами бухгалтерии в 1С начинающие разработчики часто сталкиваются с ошибкой вызова метода Выбрать(). Исключение выглядит следующим образом:

Ошибка при вызове метода контекста (Выбрать): по причине: Недопустимое значение параметра (параметр номер '3')

В этой статье мы подробно проанализируем причины возникновения этой проблемы, разберем недочеты в исходном коде и рассмотрим правильные варианты выборки данных — как через метод Выбрать(), так и с помощью запросов СУБД.

Анализ исходного кода и причин ошибки

Рассмотрим фрагмент кода, вызвавшего ошибку у автора темы:


СчетВыборка = ПланыСчетов.ЕПСБУ.НайтиПоКоду("106.31");
Счет106 = СчетВыборка.ПолучитьОбъект().Код;
СчетОтбора = Новый Структура ("Счет", Счет106);    
Выборка = РегистрыБухгалтерии.ЕПСБУ.Выбрать(Дата("20180101"),Дата("20181231"),СчетОтбора);
Пока Выборка.Следующий() Цикл       
    ДТ = Выборка.Регистратор;        
    Сообщить(ДТ.Ссылка.Дата);       
КонецЦикла;

Выясним причины, по которым платформой 1С было выброшено исключение при вызове метода Выбрать() в третьем параметре (структуре отбора):

  1. Неверный тип данных в структуре отбора: В коде выполнено обращение СчетВыборка.ПолучитьОбъект().Код. В результате в переменную Счет106 попала обычная строка "106.31". В структуре отбора для регистра бухгалтерии платформа ожидает ссылку на элемент плана счетов (тип ПланыСчетовСсылка.ЕПСБУ), а не его строковый код.
  2. Неверное имя ключа отбора: В структурах отбора ключи должны строго соответствовать именам измерений или реквизитов регистра. Если регистр бухгалтерии использует корреспонденцию счетов (что характерно для большинства бухгалтерских конфигураций, таких как ЕПСБУ или Хозрасчетный), поля Счет в регистре просто нет. Вместо него используются измерения СчетДт и СчетКт. Поле Счет присутствует только в регистрах без корреспонденции.

Дополнительные оптимизации и замечания по коду

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

  1. Избыточный вызов ПолучитьОбъект(): Метод ПланыСчетов.ЕПСБУ.НайтиПоКоду() сразу возвращает ссылку. Вызов метода ПолучитьОбъект() считывает весь объект из базы данных в оперативную память сервера, что является лишней нагрузкой при чтении данных.
  2. Лишнее обращение к свойству .Ссылка: Поле Выборка.Регистратор уже содержит ссылку на документ (ДокументСсылка). Обращение ДТ.Ссылка.Дата заставляет платформу выполнять лишнюю операцию адресации. Достаточно использовать Выборка.Регистратор.Дата.
  3. Неполная граница периода выборки: Конструкция Дата("20181231") создает дату с нулевым временем: 31.12.2018 00:00:00. Проводки, сделанные в течение дня 31 декабря, не попадут в выборку. Для охвата всего дня следует использовать функцию КонецДня().

Решение проблемы с использованием метода Выбрать()

С учетом всех исправлений сформируем корректную структуру отбора. Нам необходимо передать в отбор ссылку на счет и указать правильное имя измерения (СчетДт или СчетКт).

Рассмотрим вариант получения проводок по дебету счета:


// 1. Получаем ссылку на счет
Счет106 = ПланыСчетов.ЕПСБУ.НайтиПоКоду("106.31");

// 2. Формируем структуру отбора по измерению СчетДт
ОтборДт = Новый Структура("СчетДт", Счет106);

// 3. Выполняем выборку с умом указанной конечной даты
Выборка = РегистрыБухгалтерии.ЕПСБУ.Выбрать(
    Дата("20180101"), 
    КонецДня(Дата("20181231")), 
    ОтборДт
);

// 4. Обходим результаты
Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Регистратор.Дата);
КонецЦикла;

Обратите внимание: Если требуется выбрать все проводки, где счет участвует и по дебету, и по кредиту, сделать это в один проход метода Выбрать() невозможно. Придется выполнить две выборки (по СчетДт и по СчетКт) либо использовать запрос.

Рекомендуемый подход: Использование запросов

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

Рассмотрим разницу:

Разберем пример реализации задачи через объект Запрос:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ЕПСБУ.Регистратор.Дата КАК ДатаРегистратора
    |ИЗ
    |	РегистрБухгалтерии.ЕПСБУ КАК ЕПСБУ
    |ГДЕ
    |	ЕПСБУ.Период МЕЖДУ &ДатаНач И &ДатаКон
    |	И (ЕПСБУ.СчетДт = &Счет ИЛИ ЕПСБУ.СчетКт = &Счет)";

Запрос.УстановитьПараметр("ДатаНач", Дата("20180101"));
Запрос.УстановитьПараметр("ДатаКон", КонецДня(Дата("20181231")));
Запрос.УстановитьПараметр("Счет", ПланыСчетов.ЕПСБУ.НайтиПоКоду("106.31"));

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

Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.ДатаРегистратора);
КонецЦикла;

Таким образом, использование запросов полностью решает проблему фильтрации данных по нескольким условиям, снижает нагрузку на сеть и базу данных, а также предотвращает ошибки типов данных при передаче параметров отбора.

← На главную