在我使用的Oracle数据库中,最初以NULL精度创建了许多NUMBER列。我的理解是这些列具有隐式的最大精度。 (对于Oracle,“如果未指定精度,则该列将存储给定的值。”)它们当前包含数据。
我可以为新列明确指定的最大精度为38。但是,当我尝试修改这些现有列以设置此明确精度时,Oracle会引发错误:
ALTER TABLE test_table
MODIFY column NUMBER(38);
ORA-01440:要修改的列必须为空,以降低精度或缩放比例
如果最大为38,如何通过设置该数字来降低精度?
相对于Modify语句,更改此类型的替代方法(例如,创建新列,复制数据,删除/重新添加约束等)非常费力。
答案 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之前检查列中的实际值,因此这与现有值中的任何一个都不会超出您要指定的精度无关紧要-它只知道它们可以。