При работе с запросами в платформе 1С:Предприятие 8 разработчики часто сталкиваются с ситуацией, когда отбор по числовому реквизиту большой разрядности (например, длина 12 и более) работает некорректно. Основные симптомы проблемы: в консоли запросов невозможно ввести число длиннее 10 знаков, либо запрос, написанный в коде, возвращает пустой результат, хотя данные в базе точно есть. Проанализируем причины этого поведения и разберем способы решения проблемы.
Рассмотрим ситуацию, когда мы используем стандартную консоль запросов для проверки выборки. Чаще всего ограничение «длиной 10» возникает не из-за базы данных, а из-за особенностей самого интерфейса консоли. Выясним причину: когда мы добавляем параметр в консоль и выбираем для него тип Число, платформа по умолчанию назначает этому параметру квалификаторы (10, 0).
Проанализируем шаги, которые приводят к ошибке в консоли:
&ПорядковыйНомер.Число.123456789012 приведет к тому, что оно будет обрезано до 1234567890.Решение задачи в интерфейсе: Чтобы ввести более длинное число, необходимо при выборе типа параметра не просто нажать на «Число», а зайти в расширенную настройку типа (нажать на кнопку выбора в окне типов) и вручную изменить длину на необходимую (например, 15 или 20). Только после этого маска ввода в консоли позволит указать корректное значение.
Иногда разработчики, столкнувшись с проблемой параметров, пытаются прописать число прямо в тексте запроса (литерал). Посмотрим на пример:
ВЫБРАТЬ
Билеты.Ссылка
ИЗ
Справочник.Билеты КАК Билеты
ГДЕ
Билеты.УдалитьСумма = 1999999999999
Разберем, почему это может не работать. В платформе 8.3 существует особенность парсинга очень длинных чисел. Если число в тексте запроса превышает определенные пределы, оно может быть интерпретировано не как фиксированное десятичное число (numeric/decimal), а как число с плавающей точкой (double/float). Из-за различий в хранении этих типов в СУБД, сравнение на равенство (=) может выдавать Ложь, так как на уровне микро-значений в младших разрядах возникнет погрешность.
Вывод: Всегда используйте параметры запроса (&Параметр) вместо жестко заданных цифр. Параметры позволяют платформе более точно передать тип данных на уровень SQL-сервера.
Проанализируем ситуацию на уровне СУБД. В базе данных 1С хранит числа с фиксированной точностью. Если реквизит справочника определен как Число (12, 0), то в SQL-таблице это поле будет иметь соответствующий тип numeric(12,0).
Если мы передаем в запрос параметр, тип которого явно не задан (или задан с другой точностью), СУБД выполняет неявное приведение типов (Implicit Conversion). Это критично по двум причинам:
ГДЕ не находит совпадений.Если «не ищет в коде», необходимо проверить, как именно устанавливается параметр. Рассмотрим правильный подход к установке параметров в языке 1С. Часто ошибку совершают, передавая переменную без проверки ее типа. Выясним, как сделать это правильно:
// Предположим, ЧислоДляПоиска получено из внешнего источника или формы
ЧислоДляПоиска = 123456789012;
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| СтруктураПредприятия.Ссылка
|ИЗ
| Справочник.СтруктураПредприятия КАК СтруктураПредприятия
|ГДЕ
| СтруктураПредприятия.ПорядковыйНомер = &ПорядковыйНомер";
// Явное указание типа параметра через ОписаниеТипов гарантирует
// корректную передачу данных в SQL
ОписаниеТипаЧисло = Новый ОписаниеТипов("Число", Новый КвалификаторыЧисла(12, 0));
Запрос.УстановитьПараметр("ПорядковыйНомер", ОписаниеТипаЧисло.ПривестиЗначение(ЧислоДляПоиска));
РезультатЗапроса = Запрос.Выполнить();
Использование метода ОписаниеТипов.ПривестиЗначение() позволяет гарантировать, что в запрос уйдет число именно той разрядности, которая ожидается базой данных.
Еще один важный момент, который стоит рассмотреть — использование временных таблиц. Проанализируем ошибку:
ВЫБРАТЬ
0 КАК ПорядковыйНомер
ПОМЕСТИТЬ Вт_Данные
;
////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
СтруктураПредприятия.Ссылка
ИЗ
Справочник.СтруктураПредприятия КАК СтруктураПредприятия
ВНУТРЕННЕЕ СОЕДИНЕНИЕ Вт_Данные КАК Вт_Данные
ПО СтруктураПредприятия.ПорядковыйНомер = Вт_Данные.ПорядковыйНомер
В этом примере поле ПорядковыйНомер во временной таблице получит тип Число (1, 0), так как литерал 0 очень короткий. При последующем соединении со справочником, где длина равна 12, поиск будет работать некорректно или возникнет ошибка переполнения.
Рекомендация: Во временных таблицах всегда используйте функцию ВЫРАЗИТЬ для явного задания разрядности числовых полей:
ВЫБРАТЬ
ВЫРАЗИТЬ(0 КАК ЧИСЛО(12, 0)) КАК ПорядковыйНомер
ПОМЕСТИТЬ Вт_Данные
Подведем итог. Если запрос «обрезает» числа или не находит данные по числовому реквизиту, выполните следующие действия:
ОписаниеТипов.ВЫРАЗИТЬ, чтобы типы полей во временной таблице и в основной таблице справочника совпадали до последнего разряда.Соблюдение этих правил типизации позволит избежать трудноуловимых ошибок при работе с запросами и обеспечит высокую скорость выполнения операций в 1С.