暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

ORACLE数据类型之NUMBER详解

bestpaydata 2021-04-18
12199

Oracle可以兼容多种存储数值的数据类型,如integer,number,decimal,numberic,float,double,binary_floatbinary_float,但推荐使用NUMBER类型,因为NUMBER几乎可以表示任何复杂的数值数据,也建议在数据库开发规范中明确统一使用NUMBER数据类型来表示数值。

NUMBER类型的用法如下:

定义格式NUMBER(precision,scale)

precision表示数字中的有效位(从左边第一个不为0的数算起,小数点和负号不计入有效位数),取值范围从1到38 默认38

scale表示精确到多少位,取值范围是从-84到127 默认值取决于precision,如果没有指定precision,那么s是最大范围,如果指定了precision,那么s=0

大于零时,表示数字精确到小数点右边的位数;小于零时,将把该数字取舍到小数点左边的指定位数

所以,NUMBER整数部分允许的长度为(precision- scale),无论scale是正数还是负数,

如果precision小于scale,表示存储的是没有整数的小数

关于number p s参数遵循以下规则:

当一个数的整数部分的长度> p-s 时,Oracle就会报错

当一个数的小数部分的长度> scale时,Oracle就会舍入

当scale为负数时,Oracle就对小数点左边的s个数字进行舍入

当scale> precision时, p表示小数点后第s位向左最多可以有多少位数字,如果大于p则Oracle报错



看一下举例




上图中有一处错误哦 大家能看出来吗?



我们来看一个因为使用NUMBER类型不当造成问题的案列:

selectt1.amount,t2.amount,t1.check_key from t_XXX_bizaction t1, t_XXX_mercht2 where t1.check_key = t2.check_key

andt1.amount <> t2.amount

andt1.trade_stat=t2.trade_stat

andt1.check_key = '150101151222305822983'

andt1.check_external_stat = 'S0F';



查询中条件是<> 为何显示出来的amount都是500069呢?我们来dump一下看一下信息

select dump(amount),amount from t_XXX_bizaction wherecheck_key = '150101151222305822983';


selectdump(amount),amount from t_XXX_merch where check_key ='150101151222305822983';


dump内容的含义为:

Type1=Varchar2 2=Number 12=Date 96=Char

Len 表示占用的字节数

符号/指数位,数字1,数字2,数字3,*

符号/指数位: 最高位为1表示正数

正数:加 1 存储数字

负数:被 101 减数字 (如果总长度小于21个字节,最后加一个102,是为了排序的需要)

正数指数=符号/指数位 - 193

负数指数=62 - 符号/指数位

举例:

selectdump(123456.789) from dual;

Typ=2 Len=6: 195,13,35,57,79,91

符号/指数位=195 正数

指数=195 - 193 = 2

数字1:13 - 1 = 12 * 100^[2 - 0] = 120000

数字2:35 - 1 = 34 * 100^[2 - 1] = 3400

数字3:57 - 1 = 56 * 100^[2 - 2] = 56

数字4:79 - 1 = 78 * 100^[2 - 3] = 0.78

数字5:91 - 1 = 90 * 100^[2 - 4] = 0.009

120000 + 3400 + 56 + 0.78 + 0.009 = 123456.789

select dump(-123456.789) from dual;

Typ=2 Len=7: 60,89,67,45,23,11,102

符号/指数位:60 负数

指数=62-60=2

数字1:101 - 89 = 12 * 100[2 - 0] = 120000

数字2:101 - 67 = 34 * 100[2 - 1] = 3400

数字3:101 - 45 = 56 * 100[2 - 2] = 56

数字4:101 - 23 = 78 * 100[2 - 3] = 0.78

数字5:101 - 11 = 90 * 100[2 - 4] = 0.009

120000 + 3400 + 56 + 0.78 + 0.009 = 123456.789

还有一个102没有被计算,Oracle是为了排序的需要:

-123456.789在数据库中实际存储为:60,89,67,45,23,11

而-123456.78901在数据库中实际存储为60,89,67,45,23,11,91

-123456.789在数据库内部的存储值如果不加102,在排序上会出现-123456.78901 > -123456.789的情形

我们继续看案列中的数据:

selectdump(500069) from dual;

Typ=2Len=4: 195,51,1,70

50*100^2=500000

0*100^1=0

69*100^0=69

500000+0+69=500069

另外一个呢

Typ=2 Len=10: 195,51,1,69,100,100,100,100,100,41

50*100^2=500000

0*100^1=0

68*100^0=68

99*0.01=0.99

99*0.0001= 0.0099

99*0.000001= 0.000099

99*0.00000001= 0.00000099

99*0.0000000001= 0.0000000099

40*0.000000000001=0.00000000004

结果=500068.99999999994

select dump(500068.99999999994) from dual;

Typ=2 Len=10: 195,51,1,69,100,100,100,100,100,41

由于两个表的number类型不一致导致的问题,t_XXX_merch的amount字段类型是number,

t_XXX_bizaction的amount字段类型是number(15) ,number(15)是无法存储小数部分的

我们可以做个测试复盘这个问题:

create table test_number(col1 number,col2 number(15));

insert into test_number values (500068.99999999994,500068.99999999994);

commit;

select col1,dump(col1) dump1,col2,dump(col2) dump2from test_number;

COL1 DUMP1 COL2DUMP2

---------- -------------------------------------------------- ----------------------------------------

500069 Typ=2Len=10: 195,51,1,69,100,100,100,10 500069 Typ=2 Len=4: 195,51,1,70

0,100,41

select* from test_number where col1<>col2;

COL1 COL2

---------- ----------

500069 500069

显示一样,但是Oracle内部进行比较是不同的,col1实际上是有精度的数字

所以在生产系统中,建议使用相同的number类型,一般最好使用整数,涉及金额的可以以分为单位。


文章转载自bestpaydata,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论