ORA-01440在数据的NULL精度列上将精度设置为38时出错?

时间:2019-06-03 14:50:45

标签: database oracle

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

我可以为新列明确指定的最大精度为38。但是,当我尝试修改这些现有列以设置此明确精度时,Oracle会引发错误:

ALTER TABLE test_table
MODIFY column NUMBER(38);
  

ORA-01440:要修改的列必须为空,以降低精度或缩放比例

如果最大为38,如何通过设置该数字来降低精度?

相对于Modify语句,更改此类型的替代方法(例如,创建新列,复制数据,删除/重新添加约束等)非常费力。

2 个答案:

答案 0 :(得分:1)

您正确地引用了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

因此,您看到用最大允许精度为38不能简单地覆盖precision-这可能意味着实际下降。

类似的情况是,如果没有刻度和精度

定义了该列
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 documentation 不成立

  

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

相反,如您在以下示例中看到的,scale可能比38高:

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

select num1 from MyTable;

0,141421356237309504880168872420969807857

图中有39个十进制数字。

摘要

如果不重新组织表格,就无法设置precision

答案 1 :(得分:0)

  

我可以为新列明确指定的最大精度为38   ...

     

如果最大为38,如何通过设置该数字来降低精度?

这是您可以声明的最大值,它是NUMBER( p s )中的 p 约束。通常认为这意味着Oracle即使没有限制也不允许超过38位的数字,但这不是真的。即使您只限制规模,您也可以拥有更多。例如具有数据类型为INTEGER的列,该列没有精度约束,但标度为0。

documentation for the NUMBER data type(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.

当您查看数据时,如在numwidth设置为42的SQL Developer工作表中所报告的,您将看到:

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

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

第一行有40位有效数字,并且保留了确切的值。 (第二行丢失了插入内容中的+1,因为对于上面的引用而言,它对于内部精度而言已经太大了。在没有显式格式掩码的情况下,长度仍然报告为40,这很有趣。否则,该行就不会有帮助...)

一个INTEGER列(即NUMBER(,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之前检查列中的实际值,因此这与现有值中的任何一个都不会超出您要指定的精度无关紧要-它只知道它们可以