第二部分 数值类型
§ 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.