Как разрешить запись отрицательных чисел в колонку таблицы значений или результата запроса в 1С?

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

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

Почему возникает ошибка при попытке изменить квалификаторы?

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

Попытка изменить свойство напрямую через код:


РезультатЗапроса.Колонки.КоличествоОборот.ТипЗначения.КвалификаторыЧисла.ДопустимыйЗнак = ДопустимыйЗнак.Любой;

приводит к ошибке выполнения. Это связано со следующими правилами платформы:

  1. Объекты ОписаниеТипов и КвалификаторыЧисла являются неизменяемыми после создания. Все их свойства доступны только для чтения.
  2. Свойство ТипЗначения у объекта КолонкаТаблицыЗначений также доступно только для чтения и не может быть переопределено «на лету».
  3. При попытке присвоить отрицательное значение ячейке типизированной колонки с признаком ДопустимыйЗнак.Неотрицательный, платформа автоматически выполняет приведение к допустимому диапазону — число обращается в 0.

Рассмотрим основные способы решения этой задачи — как на уровне текста запроса, так и средствами встроенного языка при работе с таблицей значений.

Способ 1. Явное приведение типа в тексте запроса (рекомендуемый)

Наиболее эффективный и производительный подход — задать нужный тип еще на этапе формирования запроса. В языке запросов 1С функция ВЫРАЗИТЬ() для числового типа всегда возвращает поле с допустимым знаком Любой.

Посмотрим на пример текста запроса:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	ВЫРАЗИТЬ(ТоварыНаСкладахОбороты.КоличествоОборот КАК ЧИСЛО(15, 3)) КАК КоличествоОборот,
    |	ТоварыНаСкладахОбороты.Номенклатура КАК Номенклатура
    |ИЗ
    |	РегистрНакопления.ТоварыНаСкладах.Обороты(&НачалоПериода, &КонецПериода, , ) КАК ТоварыНаСкладахОбороты";

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

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

Способ 2. Выполнение арифметических операций и условных конструкций в запросе

Если знак числа или логика его расчета известны заранее, операцию можно перенести непосредственно в запрос. Любое математическое выражение (умножение, вычитание) или использование конструкции ВЫБОР КОГДА ... ТОГДА ... КОНЕЦ автоматически снимает ограничение на неотрицательность поля.

Разберем пример условной смены знака в запросе:


Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	Номенклатура,
    |	ВЫБОР
    |		КОГДА ВидДвижения = ЗНАЧЕНИЕ(ВидДвиженияНакопления.Расход)
    |			ТОГДА -Количество
    |		ИНАЧЕ Количество
    |	КОНЕЦ КАК Количество
    |ИЗ
    |	Документ.РасходнаяНакладная.Товары";

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

Способ 3. Пересоздание колонки в таблице значений

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

Разберем алгоритм по шагам:

  1. Создаем объект КвалификаторыЧисла с указанием необходимой разрядности, дробной части и допустимого знака ДопустимыйЗнак.Любой.
  2. Создаем новое ОписаниеТипов на основе числового типа и подготовленных квалификаторов.
  3. Добавляем во временную колонку таблицы значений новый тип, копируем значения и подменяем исходную колонку.

Посмотрим на программную реализацию:


// 1. Формируем описание типа с любым знаком
Квалификаторы = Новый КвалификаторыЧисла(15, 3, ДопустимыйЗнак.Любой);
НовыйТип = Новый ОписаниеТипов("Число", Квалификаторы);

// 2. Добавляем временную колонку
ТаблицаРезультат.Колонки.Добавить("КоличествоОборот_Временная", НовыйТип);

// 3. Заполняем временную колонку значениями из исходной
ТаблицаРезультат.ЗагрузитьКолонку(
    ТаблицаРезультат.ВыгрузитьКолонку("КоличествоОборот"), 
    "КоличествоОборот_Временная"
);

// 4. Удаляем старую колонку с ограничением
ТаблицаРезультат.Колонки.Удалить("КоличествоОборот");

// 5. Переименовываем временную колонку в исходное имя
ТаблицаРезультат.Колонки.КоличествоОборот_Временная.Имя = "КоличествоОборот";

Способ 4. Формирование нетипизированной таблицы значений

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

Посмотрим на пример ручного создания структуры:


// Создаем колонку без указания типа — в нее можно поместить любое значение
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура");
Таблица.Колонки.Добавить("КоличествоОборот");

Выборка = РезультатЗапроса.Выбрать();
Пока Выборка.Следующий() Цикл
    НоваяСтрока = Таблица.Добавить();
    НоваяСтрока.Номенклатура = Выборка.Номенклатура;
    
    // Вычисляем или инвертируем значение без ошибок усечения
    НоваяСтрока.КоличествоОборот = -Выборка.КоличествоОборот;
КонецЦикла;

Таким образом, для исключения ошибок записи отрицательных чисел оптимально применять функцию ВЫРАЗИТЬ() в запросе либо выполнять пересоздание колонки таблицы значений с корректным объектом ОписаниеТипов.

← На главную