查看: 40232|回复: 34

ORACLE NUMBER数据类型!

[复制链接]
论坛徽章:
57
马上加薪
日期:2014-02-19 11:55:142011新春纪念徽章
日期:2011-01-25 15:42:562011新春纪念徽章
日期:2011-01-25 15:42:332011新春纪念徽章
日期:2011-01-25 15:42:152011新春纪念徽章
日期:2011-01-25 15:41:502011新春纪念徽章
日期:2011-01-25 15:41:01ITPUB9周年纪念徽章
日期:2010-10-08 09:28:522010系统架构师大会纪念
日期:2010-09-03 16:39:572010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010新春纪念徽章
日期:2010-03-01 11:21:02
跳转到指定楼层
1#
发表于 2007-12-6 11:31 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
网上关于number的资料很多了,学习总结了下,如果问题及不足,欢迎指正。

一、oracle的number类型精度、刻度范围

number(p,s)

p:1---38
s:-84---127

有效数位:从左边第一个不为0的数算起,小数点和负号不计入有效位数。

p>0,对s分2种情况:

1. s>0

精确到小数点右边s位,并四舍五入。然后检验有效数位是否<=p;

ZWF.YUDONG>create table t_n(id number(5,2));

Table created.

ZWF.YUDONG>insert into t_n values(123.45);

1 row created.

ZWF.YUDONG>insert into t_n values(123.455);

1 row created.

ZWF.YUDONG>select * from t_n;

        ID
----------
    123.45
    123.46

2 rows selected.

ZWF.YUDONG>insert into t_n values(1.234);

1 row created.

ZWF.YUDONG>select * from t_n;

        ID
----------
    123.45
    123.46
      1.23

3 rows selected.

ZWF.YUDONG>insert into t_n values(.001);

1 row created.

ZWF.YUDONG>select * from t_n;

        ID
----------
    123.45
    123.46
      1.23
         0

4 rows selected.

ZWF.YUDONG>insert into t_n values(1234.56);
insert into t_n values(1234.56)
                       *
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column


如果s>p,小数点右边至少有s-p个0填充。

ZWF.YUDONG>create table t_n(id number(4,5));

Table created.

ZWF.YUDONG>insert into t_n values(1);
insert into t_n values(1)
                       *
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column


ZWF.YUDONG>insert into t_n values(.1);
insert into t_n values(.1)
                       *
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column


ZWF.YUDONG>insert into t_n values(.01);

1 row created.

ZWF.YUDONG>commit;

Commit complete.

ZWF.YUDONG>select * from t_n;

        ID
----------
       .01

1 row selected.

ZWF.YUDONG>insert into t_n values(.001);

1 row created.

ZWF.YUDONG>insert into t_n values(.0001);

1 row created.

ZWF.YUDONG>insert into t_n values(.00001);

1 row created.

ZWF.YUDONG>insert into t_n values(.000001);   --超过刻度存储0

1 row created.

ZWF.YUDONG>select * from t_n;

        ID
----------
       .01
      .001
     .0001
    .00001
         0


10 rows selected.

ZWF.YUDONG>col dp for a50
ZWF.YUDONG>select id,dump(id) dp,length(id),vsize(id) from t_n;  --vsize和dump的是字节数,length是数值实际位数(含小数点)

        ID DP                                                 LENGTH(ID)  VSIZE(ID)
---------- -------------------------------------------------- ---------- ----------
       .01 Typ=2 Len=2: 192,2                                          3          2
      .001 Typ=2 Len=2: 191,11                                         4          2
     .0001 Typ=2 Len=2: 191,2                                          5          2
    .00001 Typ=2 Len=2: 190,11                                         6          2
         0 Typ=2 Len=1: 128                                            1          1

5 rows selected.


2. s<0

精确到小数点左边s位,并四舍五入。然后检验有效数位是否<=p+|s|

ZWF.YUDONG>create table t_n(id number(5,-2));

Table created.

ZWF.YUDONG>insert into t_n values(12345);

1 row created.

ZWF.YUDONG>select * from t_n;

        ID
----------
     12300

1 row selected.

ZWF.YUDONG>insert into t_n values(123456);

1 row created.

ZWF.YUDONG>insert into t_n values(1234567);

1 row created.

ZWF.YUDONG>select * from t_n;

        ID
----------
     12300
    123500
   1234600

3 rows selected.

ZWF.YUDONG>insert into t_n values(12345678);
insert into t_n values(12345678)
                       *
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column


二、oracle的number类型存储结构:

oracle采用变长存储number数据类型(按一定规则进行转换成2进制编码格式存储)。

oracle数据库中存储的number类型包含3个部分: HEAD部分, DATA部分, 符号位。

对正数来说, 符号位省略, 对0来说, oracle存储的是X80(128)。

ZWF.YUDONG>select dump(0) from dual;

DUMP(0)
----------------
Typ=2 Len=1: 128

1 row selected.

ZWF.YUDONG>select dump(1) from dual;

DUMP(1)
------------------
Typ=2 Len=2: 193,2

1 row selected.

ZWF.YUDONG>select dump(-1) from dual;

DUMP(-1)
-----------------------
Typ=2 Len=3: 62,100,102   

1 row selected.

HEAD部分为一个字节8位, 就是前面看到的128, 193,62。由该部分我们可以看出number类型的基本信息,因为设计这种存储格式的时候, oracle希望以十六进制00-FF来表示所有
的number, 所以为了编码的对称, 首先将number分为正负, 所以以00-FF的中间位置80, 也就是十进制的128来表示0, HEAD部分小于80,即为负数,大于80即为正数。ORACLE再次对
00-80, 80-FF进行对分:

00-3E 表示: number <= -1
3F-7F 表示: -1 < number < 0
81-C0 表示: 0 < number < 1
C1-FF 表示:number >= 1

从HEAD部分我们可以也看出数据的位数信息,是否含有小数,可以根据HEAD的信息判断小数点的位置。由于数据部分低位2的n次方位个0是不被存储的,数据展现的时候oracle
根据HEAD的信息给补充末位的0。

ZWF.YUDONG>select dump(123456789) from dual;

DUMP(123456789)
------------------------------
Typ=2 Len=6: 197,2,24,46,68,90 --197(C5)的含义:表示数字123456789大于1,197-193(数字1占用2个字节该值为193) = 4 ,所以该数字占用6(2+4)个字节。

1 row selected.


然后,我们再来看数据部分, ORACLE对十进制的数字(整数部分,小数部分正好相反)是两位两位进行存储的(从右往左的顺序), 例如对1234, ORACLE会分别对12, 34进行存储.
所以只需要对(+-)1-99进行编码

1 --- 99 分别用十六进制2-64表示,就是2-100,

-1--- -99 用十六进制64-2表示,就是100-2

ZWF.YUDONG>select dump(12345) from dual;

DUMP(12345)
------------------------
Typ=2 Len=4: 195,2,24,46  --数据部分2,24,46 表示 (2-1=1,24-1=23,46-1=45);HEAD部分表示12345 >= 1,占用195-193+2=4字节。

1 row selected.


SYS.YUDONG>select dump(1100) from dual;  

DUMP(1100)
-------------------
Typ=2 Len=2: 194,12       --如果从右边起,连续2的n次方位为0,oracle一次排触(不存储)只是位数加1。可以对比dump(11)的情况看看。

1 row selected.

SYS.YUDONG>select dump(11) from dual;

DUMP(11)
-------------------
Typ=2 Len=2: 193,12        --这里数据部分和1100是一样的,末位的2个0没有实际存储,长度193比194小1。

1 row selected.

--对于含小数(负数、整数2种情况)的情况:

1、负数

SYS.YUDONG>select dump(-1.2) from dual;

DUMP(-1.2)
--------------------------
Typ=2 Len=4: 62,100,81,102    --HEAD=62(3E)表示该数值小于等于-1;数据部分:整数部分的-1存储为100,小数部分从左往右2位一结合,不足2位后边补一个1。
                              对应关系变为9,8...1表示1,2...9,看下面几个例子,如果足2位,还是按照上边说的规律(-1--- -99 用十六进制64-2表示,就是100-2)。

1 row selected.


ZWF.YUDONG>select dump(-2.1) from dual;

DUMP(-2.1)
-------------------------
Typ=2 Len=4: 62,99,91,102

1 row selected.

ZWF.YUDONG>select dump(-2.2) from dual;

DUMP(-2.2)
-------------------------
Typ=2 Len=4: 62,99,81,102

1 row selected.

ZWF.YUDONG>select dump(-2.9) from dual;

DUMP(-2.9)
-------------------------
Typ=2 Len=4: 62,99,11,102

1 row selected.

ZWF.YUDONG>select dump(-2.12) from dual;

DUMP(-2.12)
-------------------------
Typ=2 Len=4: 62,99,89,102

1 row selected.

ZWF.YUDONG>select dump(-2.13) from dual;

DUMP(-2.13)
-------------------------
Typ=2 Len=4: 62,99,88,102

1 row selected.

ZWF.YUDONG>select dump(-2.123) from dual;

DUMP(-2.123)
----------------------------
Typ=2 Len=5: 62,99,89,71,102

1 row selected.


2、正数

SYS.YUDONG>select dump(1.222) from dual;

DUMP(1.222)
------------------------
Typ=2 Len=4: 193,2,23,21      --HEAD=193(C1)表示该数字大于等于1;数据部分:整数部分存储2(2-1=1),小数部分从左往右2位一结合,23(23-1=22)表示22,后边还剩下一个2,
                                不足2位的末尾补充一个1,也就是等于1.2220

1 row selected.

ZWF.YUDONG>select dump(1.2220) from dual;

DUMP(1.2220)
------------------------
Typ=2 Len=4: 193,2,23,21

1 row selected.


符号位: 用的是(+-)1-99都不可能用到的编码66(102)来表示,有资料说为了处理排序问题(未加考证)。根据HEAD部分可以做初步判断,根据我们说的HEAD部分的四个范围,
如果2个数值不在一个范围,立即可以看出大小,如果在一个范围其实也可以根据其正负+绝对值来进行排序了,正数绝对值大的就大,负数则相反,为何还要用到这个符号位?


三、相关bug:

时间久了,也无从考证,写出来共享吧,也许有人会用到:

03年用9i的时候,做税收会计余额累计,当时遇到number类型的bug,数据结构为number(20,2),进行数据累计的时候当余额等于1(也许是0,印象模糊了)的时候,出现03113
错误,每次执行都一样,当时搜索了资料也说是oracle一个bug,后来采取了一些回避手段把金额先乘以100,换算完后再除以100,展现给用户,也就是利用了number(p,0)整数
类型(不存储小数部分,减少产生溢出等bug的几率)来解决了当时的问题。供参考!

http://zhouwf0726.itpub.net/post/9689/158068

论坛徽章:
33
ITPUB元老
日期:2009-03-11 15:35:03咸鸭蛋
日期:2011-11-06 22:20:25紫蛋头
日期:2011-12-27 22:15:052012新春纪念徽章
日期:2012-01-04 11:49:542014年新春福章
日期:2014-02-18 16:41:11马上有车
日期:2014-02-18 16:41:11红宝石
日期:2014-06-03 13:13:19
2#
发表于 2007-12-6 11:40 | 只看该作者
支持

使用道具 举报

回复
论坛徽章:
57
马上加薪
日期:2014-02-19 11:55:142011新春纪念徽章
日期:2011-01-25 15:42:562011新春纪念徽章
日期:2011-01-25 15:42:332011新春纪念徽章
日期:2011-01-25 15:42:152011新春纪念徽章
日期:2011-01-25 15:41:502011新春纪念徽章
日期:2011-01-25 15:41:01ITPUB9周年纪念徽章
日期:2010-10-08 09:28:522010系统架构师大会纪念
日期:2010-09-03 16:39:572010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010新春纪念徽章
日期:2010-03-01 11:21:02
3#
 楼主| 发表于 2007-12-6 11:40 | 只看该作者
补充一句:有些大型的计费系统在设计数据库结构的时候采用number(p,0)来存储数据,在数据展现的时候再除以100等(看具体需要的刻度),来换算小数部分,也是有一定的道理的,回避了一些可能存在的bug或者其他数据溢出问题!(只是自己的一些评论,不能作为设计原则的)。

使用道具 举报

回复
论坛徽章:
27
会员2007贡献徽章
日期:2007-09-26 18:42:102011新春纪念徽章
日期:2011-02-18 11:43:342010广州亚运会纪念徽章:排球
日期:2011-03-03 12:19:332010广州亚运会纪念徽章:篮球
日期:2011-03-10 14:25:06ITPUB十周年纪念徽章
日期:2011-09-27 16:30:47ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15灰彻蛋
日期:2011-12-28 16:56:322012新春纪念徽章
日期:2012-01-04 11:50:44迷宫蛋
日期:2012-03-09 15:14:20蜘蛛蛋
日期:2012-03-26 09:46:32
4#
发表于 2007-12-6 11:41 | 只看该作者
lz 辛苦

使用道具 举报

回复
论坛徽章:
2
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44生肖徽章2007版:鼠
日期:2008-01-02 17:35:53
5#
发表于 2007-12-6 11:44 | 只看该作者
幸苦,以前没有来过这个板块,刚刚投了票,不知道还能不能再投,贿赂一下斑竹……

使用道具 举报

回复
论坛徽章:
25
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:442010世博会纪念徽章
日期:2010-07-30 12:07:232011新春纪念徽章
日期:2011-02-18 11:43:332010广州亚运会纪念徽章:高尔夫球
日期:2011-04-11 18:22:37蜘蛛蛋
日期:2011-08-17 08:44:40ITPUB十周年纪念徽章
日期:2011-11-01 16:21:15复活蛋
日期:2011-12-15 09:06:552012新春纪念徽章
日期:2012-01-04 11:51:22ITPUB 11周年纪念徽章
日期:2012-10-09 18:06:202013年新春福章
日期:2013-02-25 14:51:24
6#
发表于 2007-12-6 11:46 | 只看该作者

使用道具 举报

回复
论坛徽章:
2
生肖徽章2007版:猴
日期:2008-01-02 17:35:53生肖徽章2007版:鼠
日期:2008-01-02 17:35:53
7#
发表于 2007-12-6 14:11 | 只看该作者

ddd

使用道具 举报

回复
论坛徽章:
4
授权会员
日期:2005-10-30 17:05:33ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44奥运会纪念徽章:游泳
日期:2008-10-24 13:22:072010数据库技术大会纪念徽章
日期:2010-05-13 10:08:01
8#
发表于 2007-12-6 14:12 | 只看该作者
不错,不错,顶一个!

使用道具 举报

回复
论坛徽章:
13
ITPUB新首页上线纪念徽章
日期:2007-10-20 08:38:44生肖徽章2007版:牛
日期:2009-03-10 21:33:00生肖徽章2007版:兔
日期:2009-03-10 21:27:28生肖徽章2007版:猪
日期:2009-03-10 21:24:49生肖徽章2007版:马
日期:2009-03-10 21:15:36奥运会纪念徽章:足球
日期:2008-10-24 13:28:14奥运会纪念徽章:排球
日期:2008-07-16 15:16:09生肖徽章2007版:鼠
日期:2008-01-02 17:35:53生肖徽章2007版:猴
日期:2008-01-02 17:35:53生肖徽章2007版:鸡
日期:2008-01-02 17:35:53
9#
发表于 2007-12-6 14:31 | 只看该作者
不错,学习

使用道具 举报

回复
论坛徽章:
4
生肖徽章2007版:猴
日期:2008-01-02 17:35:53生肖徽章2007版:鼠
日期:2008-01-02 17:35:53生肖徽章2007版:牛
日期:2009-04-21 11:20:532010新春纪念徽章
日期:2010-01-04 08:33:08
10#
发表于 2007-12-13 15:11 | 只看该作者
支持!

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表