Почему в запросе 1С обрезается числовой параметр и не работает отбор по длинному числу?

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

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

Особенности интерфейса «Консоли запросов»

Рассмотрим ситуацию, когда мы используем стандартную консоль запросов для проверки выборки. Чаще всего ограничение «длиной 10» возникает не из-за базы данных, а из-за особенностей самого интерфейса консоли. Выясним причину: когда мы добавляем параметр в консоль и выбираем для него тип Число, платформа по умолчанию назначает этому параметру квалификаторы (10, 0).

Проанализируем шаги, которые приводят к ошибке в консоли:

  1. Мы создаем параметр &ПорядковыйНомер.
  2. В окне выбора типа выбираем Число.
  3. Платформа автоматически ограничивает поле ввода десятью знаками. Попытка вставить число 123456789012 приведет к тому, что оно будет обрезано до 1234567890.

Решение задачи в интерфейсе: Чтобы ввести более длинное число, необходимо при выборе типа параметра не просто нажать на «Число», а зайти в расширенную настройку типа (нажать на кнопку выбора в окне типов) и вручную изменить длину на необходимую (например, 15 или 20). Только после этого маска ввода в консоли позволит указать корректное значение.

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

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


ВЫБРАТЬ
    Билеты.Ссылка
ИЗ
    Справочник.Билеты КАК Билеты
ГДЕ
    Билеты.УдалитьСумма = 1999999999999

Разберем, почему это может не работать. В платформе 8.3 существует особенность парсинга очень длинных чисел. Если число в тексте запроса превышает определенные пределы, оно может быть интерпретировано не как фиксированное десятичное число (numeric/decimal), а как число с плавающей точкой (double/float). Из-за различий в хранении этих типов в СУБД, сравнение на равенство (=) может выдавать Ложь, так как на уровне микро-значений в младших разрядах возникнет погрешность.

Вывод: Всегда используйте параметры запроса (&Параметр) вместо жестко заданных цифр. Параметры позволяют платформе более точно передать тип данных на уровень SQL-сервера.

Неявное приведение типов и SQL-индексы

Проанализируем ситуацию на уровне СУБД. В базе данных 1С хранит числа с фиксированной точностью. Если реквизит справочника определен как Число (12, 0), то в SQL-таблице это поле будет иметь соответствующий тип numeric(12,0).

Если мы передаем в запрос параметр, тип которого явно не задан (или задан с другой точностью), СУБД выполняет неявное приведение типов (Implicit Conversion). Это критично по двум причинам:

  1. Потеря производительности: При неявном приведении типов SQL-сервер не сможет использовать индекс по этому полю. Вместо быстрого поиска (Index Seek) будет выполнено полное сканирование таблицы (Index Scan), что на больших объемах данных приведет к критическим задержкам.
  2. Ошибки поиска: В редких случаях при приведении типов данных большой разрядности могут происходить ошибки округления, из-за чего условие ГДЕ не находит совпадений.

Типизация параметров в программном коде

Если «не ищет в коде», необходимо проверить, как именно устанавливается параметр. Рассмотрим правильный подход к установке параметров в языке 1С. Часто ошибку совершают, передавая переменную без проверки ее типа. Выясним, как сделать это правильно:


// Предположим, ЧислоДляПоиска получено из внешнего источника или формы
ЧислоДляПоиска = 123456789012; 

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |	СтруктураПредприятия.Ссылка
    |ИЗ
    |	Справочник.СтруктураПредприятия КАК СтруктураПредприятия
    |ГДЕ
    |	СтруктураПредприятия.ПорядковыйНомер = &ПорядковыйНомер";

// Явное указание типа параметра через ОписаниеТипов гарантирует 
// корректную передачу данных в SQL
ОписаниеТипаЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(12, 0));
Запрос.УстановитьПараметр("ПорядковыйНомер", ОписаниеТипаЧисло.ПривестиЗначение(ЧислоДляПоиска));

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

Использование метода ОписаниеТипов.ПривестиЗначение() позволяет гарантировать, что в запрос уйдет число именно той разрядности, которая ожидается базой данных.

Временные таблицы и типизация «на лету»

Еще один важный момент, который стоит рассмотреть — использование временных таблиц. Проанализируем ошибку:


ВЫБРАТЬ
    0 КАК ПорядковыйНомер
ПОМЕСТИТЬ Вт_Данные
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    СтруктураПредприятия.Ссылка
ИЗ
    Справочник.СтруктураПредприятия КАК СтруктураПредприятия
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Вт_Данные КАК Вт_Данные
    ПО СтруктураПредприятия.ПорядковыйНомер = Вт_Данные.ПорядковыйНомер

В этом примере поле ПорядковыйНомер во временной таблице получит тип Число (1, 0), так как литерал 0 очень короткий. При последующем соединении со справочником, где длина равна 12, поиск будет работать некорректно или возникнет ошибка переполнения.

Рекомендация: Во временных таблицах всегда используйте функцию ВЫРАЗИТЬ для явного задания разрядности числовых полей:


ВЫБРАТЬ
    ВЫРАЗИТЬ(0 КАК ЧИСЛО(12, 0)) КАК ПорядковыйНомер
ПОМЕСТИТЬ Вт_Данные

Резюме

Подведем итог. Если запрос «обрезает» числа или не находит данные по числовому реквизиту, выполните следующие действия:

Соблюдение этих правил типизации позволит избежать трудноуловимых ошибок при работе с запросами и обеспечит высокую скорость выполнения операций в 1С.

← На главную