Решение проблемы потери точности для колонок Oracle NUMBER без указания precision
Описание проблемы
При выгрузке данных из таблиц Oracle, если колонка объявлена как NUMBER без указания precision и scale (то есть просто NUMBER, а не NUMBER(p,s)), может возникнуть проблема с потерей точности.
В этом случае драйвер ORACLE интерпретирует тип NUMBER как DOUBLE и из-за особенностей хранения чисел с плавающей точкой происходит округление после примерно 15-17 значащего разряда. В результате выгруженные данные могут не совпадать с исходными значениями, хранящимися в Oracle.
Пример
| Декларация в Oracle | Распознанный тип | Результат |
|---|---|---|
| NUMBER | DOUBLE | Округление после 15 знака: потеря точности |
| NUMBER(38,0) | DECIMAL(38,0) | Точное значение сохраняется |
В Oracle объявление колонки как NUMBER без указания (p,s) подразумевает, что данные должны трактоваться как есть, без автоматического округления. Однако тип DOUBLE — это тип с плавающей точкой, который не способен хранить большие целые числа или значения с высокой точностью без округления.
Причина проблемы
По умолчанию Oracle ODBC-драйвер (а также некоторые ETL-коннекторы) обрабатывают тип NUMBER без указания precision как DOUBLE. Это приводит к автоматическому преобразованию в число с плавающей точкой и, соответственно, к округлению значений, если число содержит более 15-17 значащих цифр;
колонка хранит большие целые или высокоточные значения.
Решение
Чтобы сохранить полную точность для колонок NUMBER, объявленных без (p,s), необходимо включить в настройках драйвера опцию
Bind NUMBER as FLOAT:
При активированной опции драйвер связывает значения NUMBER как FLOAT, что позволяет считать и обрабатывать данные без округления, полностью соответствующие источнику.
Поведение после включения опции
| Декларация в Oracle | Распознанный тип | Результат |
|---|---|---|
| NUMBER | FLOAT | Точность сохраняется, округления нет |
| NUMBER(38,0) | DECIMAL(38,0) | Без изменений (точное представление сохраняется) |
Выводы:
| Сценарий | Поведение по умолчанию | При включённой Bind NUMBER as FLOAT |
|---|---|---|
| NUMBER без (p,s) | Интерпретируется как DOUBLE: округление после 15 цифры | Интерпретируется как FLOAT: без округления |
| NUMBER(p,s) | Интерпретируется как DECIMAL(p,s) | Без изменений |
Рекомендации
Если в вашей схеме Oracle присутствуют колонки, объявленные как NUMBER без указания precision и scale и важно сохранить точные значения (например, для идентификаторов, финансовых данных или ключей), рекомендуется включить опцию драйвера Bind NUMBER as FLOAT.
Это обеспечит сохранение точности числовых данных и предотвратит расхождения между исходными и выгруженными значениями.
Если у вас есть другие вопросы, пожалуйста, свяжитесь с нами: support@convertum.ru
