ORA-01440 ошибка установки точности 38 для столбца точности NULL с данными? - PullRequest
1 голос
/ 03 июня 2019

В базе данных Oracle, с которой я работаю, многие столбцы NUMBER были изначально созданы с точностью NULL. Насколько я понимаю, эти столбцы имеют неявную максимальную точность. (Для Oracle: «Если точность не указана, столбец хранит значения, как указано.») В настоящее время они содержат данные.

Максимальная точность, которую я могу явно указать для нового столбца, составляет 38. Однако, когда я пытаюсь изменить эти существующие столбцы, чтобы установить эту явную точность, Oracle выдает ошибку:

ALTER TABLE test_table
MODIFY column NUMBER(38);

ORA-01440: столбец, который нужно изменить, должен быть пустым для уменьшения точности или масштаба

Если 38 - максимум, как я уменьшаю точность, устанавливая это число?

Альтернативные подходы к изменению этого типа (например, создание нового столбца, копирование данных, удаление / повторное добавление ограничений и т. Д.) Довольно трудоемки по сравнению с оператором модификации.

Ответы [ 2 ]

1 голос
/ 03 июня 2019

Вы правы, цитируя Oracle, что

Если точность не указана, в столбце хранятся значения как указано

и

Максимальная точность, которую я могу явно указать для нового столбца, составляет 38

Но это не означает , что максимальная точность , которую Oracle может хранить, составляет 38 .

Вот простой пример - предположим, что ваш столбец определен без precision и с scale ноль:

create table MyTable 
(num1 NUMBER(*,0)
); 

Вы можете убедиться в этом в таблице

select COLUMN_NAME, DATA_PRECISION, DATA_SCALE 
from user_tab_columns where table_name = 'MYTABLE';

COLUMN_NAME                    DATA_PRECISION DATA_SCALE
------------------------------ -------------- ----------
NUM1                                                   0

Теперь давайте заполним некоторые данные

insert into MyTable(num1) values(sqrt(2)*power(10,38) );

На самом деле вы получили precision из 39 (я на Windows, это поведение может зависеть от ОС, но Oracle должен рассчитывать с возможностью)

select num1 from MyTable;

141421356237309504880168872420969807857

select length(to_char(num1)) from MyTable;
39

Итак, вы видите, что вы не можете просто перезаписать precision с максимально допустимой точностью из 38 - это может означать реальное уменьшение.

Аналогичная ситуация, если столбец определен без масштаба и точности

create table MyTable 
(num1 NUMBER 
); 

select COLUMN_NAME, DATA_PRECISION, DATA_SCALE 
from user_tab_columns where table_name = 'MYTABLE';

COLUMN_NAME                    DATA_PRECISION DATA_SCALE
------------------------------ -------------- ----------
NUM1                                                    

Вопреки распространенному мнению и документации Oracle в данном случае не содержит :

Если шкала не указана, шкала равна нулю.

Напротив, scale может быть выше 38, как вы видите в примере ниже:

insert into MyTable(num1) values(sqrt(2)/10);

select num1 from MyTable;

0,141421356237309504880168872420969807857

На рисунке показано 39 десятичных цифр.

Резюме

Вы не можете установить precision без реорганизации таблицы.

0 голосов
/ 03 июня 2019

Максимальная точность, которую я могу явно указать для нового столбца, составляет 38 ...

Если 38 - максимум, как я уменьшаю точность, устанавливая это число?

Это максимум, который вы можете объявить как ограничение p в NUMBER ( p , s ). Часто считается, что Oracle не допускает числа более 38 цифр, даже если они не ограничены, но это не совсем так. Даже если вы ограничиваете масштаб, вы можете иметь больше; например со столбцом типа данных INTEGER, который не имеет ограничения точности, но имеет масштаб 0.

Документация для типа данных NUMBER (12cR2) включает в себя:

Oracle гарантирует переносимость чисел с точностью до 20 цифр от 100 до 100, что эквивалентно 39 или 40 десятичным цифрам

С колонкой с неограниченной точностью вы можете иметь более 38 значащих цифр. Некоторые примеры таблиц для демонстрации:

create table t1 (num number);
create table t2 (num integer);
create table t3 (num number(38));
create table t4 (num number(38,0));

select table_name, column_name, data_type, data_length, data_precision, data_scale
from user_tab_columns
where table_name in ('T1', 'T2', 'T3', 'T4');

TABLE_NAME COLUMN_NAME  DATA_TYPE DATA_LENGTH DATA_PRECISION DATA_SCALE
---------- ------------ --------- ----------- -------------- ----------
T1         NUM          NUMBER             22                          
T2         NUM          NUMBER             22                         0
T3         NUM          NUMBER             22             38          0
T4         NUM          NUMBER             22             38          0

тогда это разрешено:

insert into t1 values (power(10, 39)+1);

как, собственно, это:

insert into t1 values (power(10, 40)+1);

1 row inserted.

Когда вы смотрите на данные, как указано в рабочем листе SQL Developer с numwidth, установленным на 42, вы видите:

select num, length(to_char(num)) from t1;

                                       NUM                       LENGTH(TO_CHAR(NUM))
------------------------------------------ ------------------------------------------
  1000000000000000000000000000000000000001                                         40
 10000000000000000000000000000000000000000                                         40

Первая строка имеет 40 значащих цифр, и точное значение сохраняется. (Вторая строка потеряла +1 от вставки, так как теперь она слишком велика для внутренней точности в приведенной выше цитате. Длина по-прежнему указывается как 40 без явной маски форматирования, что немного интересно. В противном случае эта строка не полезно ...)

Столбец INTEGER, который является НОМЕРОМ (, 0), допускает то же самое:

insert into t2 values (power(10, 39)+1);

1 row inserted.

select num, length(to_char(num)) from t2;

                                       NUM                       LENGTH(TO_CHAR(NUM))
------------------------------------------ ------------------------------------------
  1000000000000000000000000000000000000001                                         40

Но как только вы ограничите точность, которая больше не разрешена:

insert into t3 values (power(10, 39)+1);

ORA-01438: value larger than specified precision allowed for this column

insert into t3 values (power(10, 38)+1);

ORA-01438: value larger than specified precision allowed for this column

insert into t3 values (power(10, 37)+1);

1 row inserted.

select num, length(to_char(num)) from t3;

                                       NUM                       LENGTH(TO_CHAR(NUM))
------------------------------------------ ------------------------------------------
    10000000000000000000000000000000000001                                         38

Если вы также ограничите масштаб до нуля, он будет вести себя одинаково; вставка и запрос t4 дает те же результаты.

Итак, суть в том, что простой столбец NUMBER равен , а не , как столбец NUMBER(38, 0), и ваш оператор alter равен , фактически снижая теоретическую максимальную точность колонны. Oracle не проверяет фактические значения в столбце перед выдачей ORA-01440, поэтому не имеет значения, что ни одно из существующих значений фактически не превышает точность, которую вы пытаетесь указать, - он просто знает, что они могут .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...