Database ORA-01440在包含数据的空精度列上设置精度为38时出错?

Database ORA-01440在包含数据的空精度列上设置精度为38时出错?,database,oracle,Database,Oracle,在我使用的Oracle数据库中,许多数字列最初是以NULL精度创建的。我的理解是,这些列具有隐含的最大精度。(根据Oracle:“如果未指定精度,则列存储给定的值。”)它们当前包含数据 我可以为新列显式指定的最大精度为38。但是,当我试图修改这些现有列以设置此显式精度时,Oracle会抛出一个错误: ALTER TABLE test_table MODIFY column NUMBER(38); ORA-01440:要修改的列必须为空,以降低精度或比例 如果38是最大值,我如何通过设置该数字来

在我使用的Oracle数据库中,许多数字列最初是以NULL精度创建的。我的理解是,这些列具有隐含的最大精度。(根据Oracle:“如果未指定精度,则列存储给定的值。”)它们当前包含数据

我可以为新列显式指定的最大精度为38。但是,当我试图修改这些现有列以设置此显式精度时,Oracle会抛出一个错误:

ALTER TABLE test_table
MODIFY column NUMBER(38);
ORA-01440:要修改的列必须为空,以降低精度或比例

如果38是最大值,我如何通过设置该数字来降低精度

与modify语句相比,更改此类型的其他方法(例如,创建新列、复制数据、删除/重新添加约束等)相当费劲

我可以为新列显式指定的最大精度为38

如果38是最大值,我如何通过设置该数字来降低精度

这是您可以声明的最大值,作为数量(p,s)中的p约束。人们经常认为这意味着Oracle不允许超过38位的数字,即使是不受限制的数字,但事实并非如此。即使只约束比例,也可以获得更多;e、 g.数据类型为INTEGER的列,该列没有精度约束,但刻度为0

(12cR2)包括:

Oracle保证数字的可移植性,精度高达20位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,没有显式的格式掩码,这有点有趣。否则该行没有帮助…)

整数列(即数字(,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之前不会检查列中的实际值,因此,现有值中没有一个实际超过您试图指定的精度并不重要,它只知道它们可能会超过精度。

您引用Oracle的说法是正确的

如果未指定精度,该列将按给定值存储值

我可以为新列显式指定的最大精度为38

但是并不意味着Oracle可以存储的最大精度是38

这里是一个简单的示例-假设您的列是在没有
精度
比例
为零的情况下定义的:

create table MyTable 
(num1 NUMBER(*,0)
); 
您可以在Discitionary表中对此进行验证

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) );
实际上,您的
精度为39(我在Windows上,这种行为可能依赖于操作系统,但Oracle必须考虑到这种可能性)

因此,您不能简单地用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                                                    
与流行的观点相反,在这种情况下,不成立:

如果未指定比例,则比例为零

相反,
刻度可能高于38,如下例所示:

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

select num1 from MyTable;

0,141421356237309504880168872420969807857
图中有39位小数

摘要


如果不重新组织表格,则无法设置
精度。

编号(38,6)
?当前列是否有此
编号类型的刻度?如果不指定一个刻度,则您将刻度设置为0,这可能是一种减少。事实上,尽管该列没有刻度。这是一个很好的答案,谢谢。“如果不重新组织表格,就无法设置精度。”-->不幸的是,这正是我试图避免的。这是一个与上面的答案一样好的答案,我希望我能选择两者。非常感谢。
insert into MyTable(num1) values(sqrt(2)/10);

select num1 from MyTable;

0,141421356237309504880168872420969807857