【问题标题】:data length v/s data precision数据长度v/s数据精度
【发布时间】:2020-10-24 04:09:25
【问题描述】:

有一列 data_type NUMBER , data_length 22 , data_precision 5, data_scale 1。 这意味着它可以容纳最大值为 9999.9 要求是 - 我必须使该列容纳最大值为 9999.99 即 data_precision 6 和 data_scale 2 。 我想知道这里 data_length 的意义是什么? 我是否必须更改它的精度和比例,或者它将容纳 9999.99 而无需进行任何更改,因为长度已经是 22

【问题讨论】:

  • 我认为data_precisiondata_scalenumber 的建议。对于numeric/decimal,它们被强制执行。

标签: sql oracle types


【解决方案1】:

考虑到 Oracle 的定义:

DATA_LENGTH 是列的长度(以字节为单位)。 DATA_PRECISION 是 NUMBER 数据类型的十进制精度,FLOAT 数据类型的二进制精度,所有其他数据类型的 null。 DATA_SCALE是数字中小数点右边的数字

举个例子:

SQL> create table check_size ( c1 number, c2 number(6) , c3 number(6,3) );

Table created.

SQL> set lines 200
SQL> r
  1  SELECT COLUMN_NAME,
  2            DATA_TYPE,
  3            DATA_LENGTH,
  4               DATA_PRECISION,
  5               DATA_SCALE
  6              FROM ALL_TAB_COLS
  7      WHERE OWNER='TEST'
  8*     AND TABLE_NAME = 'CHECK_SIZE'

COLUMN_NAME                    DATA_TYPE                      DATA_LENGTH DATA_PRECISION DATA_SCALE
------------------------------ ------------------------------ ----------- -------------- ----------
C1                             NUMBER                                  22
C2                             NUMBER                                  22              6          0
C3                             NUMBER                                  22              6          3

如您所见,data_length 始终为 22。那是因为数字是作为数据包存储的,所以字典会始终显示 22,但我可以插入大于 22 位的数字。

SQL>  insert into check_size values ( 99999999999999999999999999999999999999999999 , 999999, 999.99 );

1 row created.

SQL> select dump(c1) as content from check_size ;

CONTENT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Typ=2 Len=2: 215,2

但是,在您的情况下,您说的是数据精度 5 和数据规模 1,所以让我们截断表并修改列:

SQL> truncate table check_size ;

Table truncated.

SQL> alter table check_size modify c3 number ( 5,1 );

Table altered.

SQL>  insert into check_size values ( 99999999999999999999999999999999999999999999 , 999999, 99 );

1 row created.

SQL>  insert into check_size values ( 99999999999999999999999999999999999999999999 , 999999, 9999.9 );

1 row created.

SQL>  insert into check_size values ( 99999999999999999999999999999999999999999999 , 999999, 9999.99 );
 insert into check_size values ( 99999999999999999999999999999999999999999999 , 999999, 9999.99 )
                                                                                        *
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column

总结一下,使用数据比例 5 和数据精度 1,您可以存储任何类型的数字,直到最大精度 + 比例。所以我可以存储 9999.9 和 99(比例和精度是建议性的),但我不能 9999.99,因为我的比例是 1,这里的数字有 2 个小数。

希望它澄清 问候

【讨论】:

    【解决方案2】:

    由于列的数据长度为 (22, 5),因此它也可以容纳 (6, 2)。如果您仍想将数据长度限制为 (6, 2) 以满足任何技术/业务需求,您可以使用下面的 alter 语句来修改您的列。

    alter table table_name modify column_name number(6, 2);
    

    【讨论】:

      【解决方案3】:

      基本上,DATA_LENGTH 对数字列没有意义。它适用于 CHAR/VARCHAR 类型。如果类型是数字,只需查看 DATA_PRECISION 和 DATA_SCALE。

      同样对于数字类型,DATA_LENGTH 是以字节为单位的最大存储大小。但是,与 CHAR/VARCHAR 类型相比,类型参数(在本例中为精度和小数位数)没有考虑在内:为所有数字类型设置了值 22,即使它们受到如此限制以至于它们实际上永远无法达到 22 个字节。

      我认为值22的原因如下:

      • Oracle 将两位数字存储在一个字节中。由于 NUMBER/NUMERIC 在 Oracle 中官方支持最多 38 位,可能有人认为这需要最多 19 个字节。但是,Oracle 内部使用(尾数,指数)表示,其中指数相对于以 100 为底,而不是以 10 为底(因为一个字节中的两个数字可以被视为一个以 100 为底的数字)。现在,如果小数点位于奇数位置,则第一个和最后一个字节实际上只包含一个数字。因此,需要 20 个字节。实际上,可以在 NUMBER 类型的列中存储 39 位甚至 40 位(取决于小数点位置)的数字。 这也支持 20 字节假设。
      • 指数需要一个字节(以 100 为底)。
      • 如果数字为负数,则需要一个额外的字节。

      可以使用VSIZE函数检查存储长度:

      SELECT VSIZE(-12345678901234567890123456789012345678)
      FROM DUAL
      

      结果是 21(如预期的那样)。没有减号,就是 20。

      不幸的是,我无法通过添加更多数字来获得值 22。如果再增加一位,则得到正数的值 21:

      SELECT VSIZE(123456789012345678901234567890123456789)
      FROM DUAL
      

      这看起来不错。但是,如果现在将这个数字设为负数,结果仍然是 21(而对于我测试的所有较小的数字,将数字设为负数会增加一个字节)。 [我使用的是 Oracle 18c XE。]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-01-20
        • 1970-01-01
        • 2018-07-12
        • 2015-05-06
        • 2012-03-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多