• 转Oracle数据类型及存储方式【C】


    第二部分 数值类型
    § 2.1  number
    Number类型是oralce的数值类型,存储的数值的精度可以达到38位。Number是一种变长类型,长度为0-22字节。取值范围为:10e-130 – 10e 126(不包括)
    Number(p,s)
    P和s都是可选的。
    P指精度(precision),即总位数。默认情况下精度为38。精度的取值范围为1~38.
    S指小数位(scale).小数点右边的位数。小数点位数的合法值为-48~127。小数位的默认值由精度来决定。如果没有指定精度,小数位默认为最大的取值区间.如果指定了精度,没有指定小数位。小数位默认为0(即没有小数位).
    精度和小数位不会影响数据如何存储,只会影响允许哪些数值及数值如何舍入。


    1.新建一个表
    SQL> create table test_number(col_number number(6,2));

    Table created
    2.插入一些不同的数据
    SQL> insert into test_number values(-1);

    1 row inserted

    SQL> insert into test_number values(0);

    1 row inserted

    SQL> insert into test_number values(1);

    1 row inserted

    SQL> insert into test_number values(2);

    1 row inserted

    SQL> insert into test_number values(11.00);

    1 row inserted

    SQL> insert into test_number values(11.11);

    1 row inserted

    SQL> insert into test_number values(1234.12);

    1 row inserted

    SQL> insert into test_number values(-0.1);

    1 row inserted

    SQL> insert into test_number values(-11.11);

    1 row inserted

    SQL> insert into test_number values(-1234.12);

    1 row inserted
    SQL> commit;

    Commit complete

    3.查看结果
    SQL> select * from test_number;

    COL_NUMBER
    ----------
         -1.00
          0.00
          1.00
          2.00
         11.00
         11.11
       1234.12
         -0.10
        -11.11
      -1234.12

    10 rows selected

    5. 查看存储结构
    SQL> select col_number, dump(col_number) from test_number;

    COL_NUMBER DUMP(COL_NUMBER)
    ---------- --------------------------------------------------------------------------------
         -1.00 Typ=2 Len=3: 62,100,102
          0.00 Typ=2 Len=1: 128
          1.00 Typ=2 Len=2: 193,2
          2.00 Typ=2 Len=2: 193,3
         11.00 Typ=2 Len=2: 193,12
         11.11 Typ=2 Len=3: 193,12,12
       1234.12 Typ=2 Len=4: 194,13,35,13
         -0.10 Typ=2 Len=3: 63,91,102
        -11.11 Typ=2 Len=4: 62,90,90,102
      -1234.12 Typ=2 Len=5: 61,89,67,89,102

    10 rows selected

    由此可见:
    Number类型的内部编码为:2
    根据每一行的len值可以看出,number是一个变长类型。不同的数值占用不同的空间。
    如果指定了精度,显示结果与精度相关。
    就像我插入语句写为
    insert into test_number values(0);
    但是显示结果为:0.00
    如果数值是负数,在最后一位上填充一个补码102.即表示该数值为负数。
    0是一个特殊的值,它在oracle中存储为128.
    第一位为标志位。以128为比较。如果数值大于128,则它大于0。如果小于128小于0。
    -1的内部存储为:
    -1.00 Typ=2 Len=3: 62,100,102
    最后一位是102,是一个负数。
    第一位小于128,所以小于10.
    除了第一位标志位外,其它的都是数值为了。
    如果该值是一个正数。每一位的存储值减1为每一位的实际值。
    1.0的存储结构为:
    1.00 typ=2 Len=2: 193,2
    实值上1.00的存储结果与1相同。
    第一位193为标志位,大于128,大于0.
    第二位为数值为,因为是正数,实际值为存储值减1。2-1 = 1。
    如是该值是一个负数,每一位的实际值为101 减去存储的值。
    -1.00的存储结构为:
    -1.00 Typ=2 Len=3: 62,100,102
    最后一位102为补位。
    第一位62为标志位,小于128。实际值小于0.
    第二位为数值为,因为是负数。实际值为:101 – 100  =1.

    §2.2 小数位在哪里?
    从上面的存储结果看,对小数存储时,它并没有一个小数的标志位。但是它实际上是由第一位标志位,和数值位(第二位)来决定的。
    当存储的数是一个正数,该数值的前几位为:第一位 * power(100 , (标志位 - 193));
    当存储的数是一个负数,该数值的前几位为:第一位 * power(100,(62 – 标志位));
    11.11的存储结果为:
    11.11 Typ=2 Len=3: 193,12,12
    第一位数值位为:12 实际数值为11
    标志位为:193
    12 * power(100, (193- 193);
       100的零次方为1.
    12 乘1 等于12.
    所以这个数的前几位为:12。从这后面就是小数了。
    1234.12的存储结构为:
    1234.12 Typ=2 Len=4: 194,13,35,13
    第一位数值位为:13,实际值为12
    标志位为:193
    13 * power(100,(194-193)) = 1300
    所以前四位为整数位,后面的为小数位。


    -0.10的存储结构为:
    -0.10 Typ=2 Len=3: 63,91,102
    标志位为:63
    第一位数值为:91 ,实际值为:10
    91 * (100,(62-63)) =-9100.
    所以小数位在91之前。

    -1234.12的存储结构为:
    -1234.12 Typ=2 Len=5: 61,89,67,89,102
    标志位为:61
    第一位数值为:89
    89*(100,(62-61)) =8900
    所以小数位在67之后。
    §2.3 number的精度和小数位
    Number类型的精度最多可是38位。小数位-84--127位。
    SQL> create table test_number1(col_number number(39));

    create table test_number1(col_number number(39))

    ORA-01727: numeric precision specifier is out of range (1 to 38)
    指定小数位时,精度只能是1-38。不能是0
    SQL> create table test_number1(col_number number(0,127));

    create table test_number1(col_number number(0,127))

    ORA-01727: numeric precision specifier is out of range (1 to 38)



    SQL> create table test_number1(col_number number(1,128));

    create table test_number1(col_number number(1,128))

    ORA-01728: numeric scale specifier is out of range (-84 to 127)

    精度与小数位的关系。精度并不是小数位加整数位之和。
    我们先看看小数位为0的情况。
    SQL> create table test_number1(col_char varchar2(200), col_num number(10));

    Table created
    Number(10).只定义了精度,小数位为0.
    看看它可以存放的数据。


    SQL> insert into test_number1 values('9999999999',9999999999);

    1 row inserted

    插入了10个9,没有问题,再插入多一位看看
    SQL> insert into test_number1 values('99999999991',99999999991);

    insert into test_number1 values('99999999991',99999999991)

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

    报错了,精度不够。
    再看看能不能再插入小数?
    SQL> insert into test_number1 values('0.9',0.9);

    1 row inserted


    SQL> select * from test_number1;

    Col_char COL_NUM
    -------------------- --------------
    9999999999 9999999999
    0.9              1

    注意插入数值0.9后,存储为1.这就是小数位的作用。在哪里进行舍入。

    带小数位和精度的情况。
    SQL> create table test_number2(col_char varchar(20),col_num number(1,3));

    Table created
    精度是1,小数位是3.
    可见,精度不是小数位加整数位了。但是精度和小数位倒底什么关系呢?
    SQL> insert into test_number2 values('0.111',0.111);

    insert into test_number2 values('0.111',0.111)

    ORA-01438: value larger than specified precision allowed for this column
    插入3位小数,0.111竟然报错了,说精度不够。
    SQL> insert into test_number2 values('0.001',0.001);

    1 row inserted
    插入0.001时,成功了。
    SQL> insert into test_number2 values('0.001',0.0015);

    1 row inserted
    插入0.0015也成功了。
    看看插入的值。
    SQL> select * from test_number2;

    COL_CHAR             COL_NUM
    -------------------- -------
    0.001                  0.001
    0.0015                 0.002
    需要注意的是0.0015被舍入为0.002

    精度大于小数位
    SQL> create table test_number3 (col_char varchar(20), col_number number(5,3));

    Table created

    SQL> insert into test_number3 values('99.899',99.899);

    1 row inserted

    SQL> insert into test_number3 values('99.999',99.999);

    1 row inserted

    SQL> insert into test_number3 values('99.9999',99.9999);

    insert into test_number3 values('99.9999',99.9999)

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

    注意,当插入99.9999时,系统报错。因为小数位为3位。第四位小数位是9,于是往前入。最终变成100.000.就已经超过了精度。
    Number(5,3)可存储的数值最大为99.999.
    现在终于有点明白小数位与精度的关系了。

    number(38,127)
    可以存储的最大小数为:127位小数,最后38为9.
    即:0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000099999999999999999999999999999999999999

    小数位为负数。
    我们从前面知道,小数位的取值为-48 ~127
    为什么小数位会为负数?这有点怪异了。像上面的number(5,3)将值舍入为最接近0.001
    Number(5,-3)就是将值舍入为最接近的1000

    SQL> create table test_number5 (col_char varchar(20), col_num number(5,-3));

    Table created

    插入值10999
    SQL> insert into test_number5 values('10999',10999);

    1 row inserted
    查看一下结果
    SQL> select * from test_number5;

    COL_CHAR             COL_NUM
    -------------------- -------
    10999                  11000
    存储的结果为:11000
    当小数部分为负数时,是对小数部分进行舍入。

    那么精度在这时起到什么作用呢?与小数位又有什么关系?
    SQL> insert into test_number5 values('111111111',111111111);

    insert into test_number5 values('111111111',111111111)

    ORA-01438: value larger than specified precision allowed for this column
    插入9个1时,报错精度不够。
    SQL> insert into test_number5 values('11111111',11111111);

    1 row inserted
    插入8个1时,正确插入。
    我们看看它的结果,看它是怎么舍入的。
    SQL> select * from test_number5;

    COL_CHAR             COL_NUM
    -------------------- -------
    11111111             11111000

    结果是1111100而不是1111100
    无限接近1000,就是从百位开始进行四舍五入,后面的值全部为0。
    所以看出number(5,-3)可存储的最大值为:99999000
    SQL> insert into test_number5 values('99999499.999999',99999499.999999);

    1 row inserted

    SQL> select * from test_number5;

    COL_CHAR             COL_NUM
    -------------------- -------
    99999999             99999000
    99999499.999999      99999000

    现在应该明白了精度和小数位的关系了吧。
    小数位告诉系统保留多少位小数,从哪里开始舍入。
    精度舍入后,从舍入的位置开始,数值中允许有多少位。

    §2.4  binary_float 和binary_double
    这两种类型是oracle 10g新引进的数值类型。在oracle 10g之前是没有这两种类型的。
    Number类型是由oracle软件支持的类型。而浮点数用于近似数值。但是它浮点数允许由在硬盘上(CPU,芯片)上执行运行。而不是在oracel进程中运算。如果希望在一个科学计算中执行实数处理,依赖于硬件的算术运算速度要快得多。但是它的精度却很小。如果希望用来存储金融数值,则必须用number.
    BINARY_FLOAT是一种IEEE固有的单精度浮点数。可存储6位精度,取值范围在~±1038.25的数值。
    BINARY_DOUBLE是一种IEEE固有的双精度浮点数。可存储12位精度。取值范围在~±10308.25的数值
    SQL> create table test_floatdouble(col_number number, col_float binary_float, col_double binary_double);

    Table created

    SQL> insert into test_floatdouble values(9876543210.0123456789,9876543210.0123456789,9876543210.0123456789);

    1 row inserted
    2 SQL> select to_char(col_number), to_char(col_float), to_char(col_double) from test_floatdouble;
    3
    4 TO_CHAR(COL_NUMBER)                      TO_CHAR(COL_FLOAT)                       TO_CHAR(COL_DOUBLE)
    5 ---------------------------------------- ---------------------------------------- ----------------------------------------
    6 9876543210.0123456789                    9.87654349E+009                          9.8765432100123463E+009

    由此可见,binary_float无法表示这个数。Binary_float和binary_double无法用于对精度要求高的数据。



    SQL> select dump(col_float)from test_floatdouble;

    DUMP(COL_FLOAT)
    --------------------------------------------------------------------------------
    Typ=100 Len=4: 208,19,44,6

    BINARY_FLOAT 类型编码为100
    Len=4 占用4个字节。它是采用固定字节进行存储的。

    SQL> select dump(col_double)from test_floatdouble;

    DUMP(COL_DOUBLE)
    --------------------------------------------------------------------------------
    Typ=101 Len=8: 194,2,101,128,183,80,25,73

    BINARY_DOUBLE 类型编码为101
    Leng= 8 占用8个字节。也是采用固定字节进行存储。

    注意:number 类型使用的CPU时间是浮点数类型的50倍。浮点数是数值的一个近似值,精度在6-12位之间。从Number类型得到的结果要比从浮点数得到的结果更精确。但在对科学数据进行数据挖掘和进行复杂数值分析时,精度的损失是可以接受的,还会带来显著的性能提升。
    这时需要使用内置CAST函数,对NUMBER类型执行一种实时的转换,在执行复杂数学运算之前先将其转换为一种浮点数类型。CPU使用时间就与固有浮点类型使用的CPU时间非常接近了。
    Select ln(cast(number_col as binary_double)) from test_number.

    §2.5 Oracle在语法上还支持的数值数据类型
    NUMERIC(p,s):完全映射到NUMBER(p,s)。如果p未指定,则默认为38.
    DECIMAL(p,s)或DEC(p,s):同NUMERIC(p,s).
    INTEGER或int:完全映射至NUMBER(38)
    SMALLINT:完全映射至NUMBER(38)
    FLOAT(b):映射至NUMBER
    DOUBLE PRECISION:映射到NUMBER
    REAL:映射到NUMBER.
  • 相关阅读:
    2、react-生命周期1※※※
    4.vue class 绑定- model基础应用
    1.react的基础
    Leetcode 5429 数组中的 k 个最强值
    leetcode 21.合并两个有序链表(迭代)
    【Postman请求无响应】Can not get any response
    【PageHelper】插件不生效的原因及解决办法
    【fasterxml.jackson】字段(反)序列号问题Access.WRITE_ONLY
    【SpringCloud-Maven】依赖版本比对
    【Charles】抓包工具使用
  • 原文地址:https://www.cnblogs.com/linsond/p/1767965.html
Copyright © 2020-2023  润新知