oracle数值类型漫谈
发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,这片博客本来想的是只写pls_integer与number之间的性能比较,但是提笔之后我又想写更多我的思考过程,于是索性写一篇关于oracle数值类型的文章。干货太多,未免看得乏味,本篇我尝试用一种聊
千家信息网最后更新 2025年02月02日oracle数值类型漫谈这片博客本来想的是只写pls_integer与number之间的性能比较,但是提笔之后我又想写更多我的思考过程,于是索性写一篇关于oracle数值类型的文章。干货太多,未免看得乏味,本篇我尝试用一种聊天谈话的方式行文,希望同行者可以在一种轻松的氛围中和我一起来探讨oracle的诸多数值类型,好吧,那我就先抛砖引玉了。
1、number
我最先接触的数值类型就是老大哥number,它定义为number(p,s),p是精度,最大38位,s是刻度范围,可在-84~127间取值。举个栗子(例子):number(4,2),指的就是小数点整数+小数部分一共有4位,不包含小数点位,也就是说整数部分最多两位,如果小数部分多于2位,会做四舍五入处理(对于sqlserver和mysql也会做四舍五入处理),如果小数部分不足2位的话,则会补0(对于sqlserver也会补0,但是mysql不会),如果不写p,s,那么就默认为38。number类型是oracle最常用的数字类型了,在很长一段时间之内,我以为数值类型就只有number,因为number类型足以处理几乎全部的数字类型了。但是之后在oracle道路上继续行走的过程中,我又认识了其他衍生的数值类型。
2、integer
其实最开始看到这个数值类型的时候,同很多人一样,我也认为它是number类型的子类型,最大38位,对于小数做自动四舍五入处理,但是后来我发现不完全是这样的。作为number的子类型不假,一般情况下,integer是作为存储整数值存在的,在需要存储整数值的时候我们会想到这个数值类型,但是它的最大位可不是38位,在插入的测试数值看到,它已经远远超过38位了,如图:
可以看到,对于integer只能存储38位的言论可谓是直接推翻。接下来我们来看坊间盛传的,"integer只能存储整数,对于小数会做四舍五入处理",来看一个例子:
create or replace procedure integer_test(a integer)
as
b integer := a;
begin
dbms_output.put_line(b);
end;
输出结果如图:
看到这个结果的时候,相信很多同学都已经凉了,简直是颠覆了以往的认识啊,的确,从这个例子可以看出,integer是number的子类型,但是它不会强制进行四舍五入处理,同时它最大位数大于38位。
3、int,numeric,decimal
这三种数值类型是oracle为了兼容其他数据库而存在的,同样都是number的子类型。在进行类型声明的时候,如果直接声明为int,numeric,decimal,它会被直接存为integer,处理方式同integer一模一样;numeric和decimal如果带有精度和刻度范围,那么会被存为number(p,s),处理方式同number(p,s),int类型只能被声明为int,不能带精度和刻度范围,所以只能当作integer来处理。
4、float
float也是number的子类型,float(n),n指的是精度,是二进制精度,这里可不是十进制精度哦,计算公式为:binary precision=ceil(b*0.30103),float没有刻度范围.n的范围为1~126。那么怎么计算存入数据库中的数值呢,比如:float(2),那么它的精度是ceil(2*0.30103)=1,如果存入13.5,那么应该是1.35*10^1,精度为1,1.35四舍五入变为1,所以就是1*10^1=10存入的结果就是10;如果是19.5,那么应该是1.95*10^1,精度为1,1.95四舍五入为2,就是2*10^1,结果存入20。如果没有精度,那么映射为number类型,直接存入此值。oracle没有直接为double类型的数值类型。
5、binary_integer和pls_integer
这个数字类型只能用于PL/SQL,他们相比number来说更具优势,首先是占有较少的存储空间,其次他们是直接通过硬件来计算的,也就是直接通过CPU进行计算,而不用经过转换,number类型在计算的时候,还要先被转换为二进制,所以在计算速度上,binary_integer和pls_integer比number性能好很多,建议在PL/SQL中使用这两种数据类型来代替number,你将会得到很大的惊喜。
5、binary_float和binary_double
这两种数值类型10g之后才出现,binary_float可以存储一个单精度的32位浮点数,binary_double可以存储一个双精度的64位浮点数,binary_float和binary_double占有更少的存储空间,同样的,binary_float和binary_double也是直接通过硬件计算的,所以它的计算效率更高,而且它们比起number来说可以存储更大或者更小的数值,但是这两种数值类型也会存在精度不准的情况。
6、写到浮点型,我需要说一说浮点型存数不精确的原因:
首先,我们要知道浮点型在计算机是怎么存储的,比如:要存入13.75,首先将整数部分转为二进制,13转为二进制是1101,接下来将小数部分转为二进制,小数部分是0.75,将小数部分乘以2,取结果的整数部分为二进制的一位,然后继续取结果的小数部分乘以2重复,一直到小数部分全部为0结束,在这个过程中,是会出现循环乘不尽的情况,但是因为浮点数的小数位是确定的(float是23位,double是52位),所以到了指定的小数位就会停下来,这就是浮点数存数不精确的原因,可以看到如果可以在小数位范围之内乘尽的话,那么结果就存储的准确了。来看看小数部分(0.75)转为二进制的过程:
0.75*2=1.5 取1
0.5*2=1 取1
乘到这里,即0.5*2=1,1已经没有小数部分了,所以到这里也就停止了,最后的结果是0.11,与上面整数部分合起来,那么13.75转换为二进制为1101.11,即1.10111*2^3,1.10111是小数部分,2为底,6为指数部分,这个1.10111*2^3就是转换好的二进制浮点数,接着就是将这个二进制浮点数存入计算机了。
将其存入计算机内,将会使用浮点表示法,分为三大部分:
第一部分:符号位,占用1位,用来区分正负数,0为正数,1为负数;对于1.10111*2^3,它是正数,所以符号位是0
第二部分:指数位,float占用8位,double占用11位,用来表示指数;对于1.10111*2^3,指数位是3
第三部分:小数位,float占用23位,double占用52位,用来表示小数,不足位数补0;对于1.10111*2^3,小数位是10111
所以对于float,符号位+指数位+小数位=1+8+23=32位,对于double,符号位+指数位+小数位=64位,同时可以看到,指数位决定了大小范围,小数位决定了精度。因为指数位有可能是正数,也有可能是负数,负数算起来比正数麻烦,所以为了减少计算的麻烦,在存储指数的时候,需要将它存储位无符号的整数,所以在指数位上会加一个偏移量,float的偏移量是127,double的偏移量是1023,如果需要转换为十进制的话,到时候指数减去相应的值就可以了。那么对于13.75(float),本来它的二进制指数值是3,现在就成了3+127=130,转换为二进制是10000010,最终:13.75(float)被存储为:符号位 指数位 小数位(不足位补0)=0 10000010 10111 00000 00000 00000 000
7、万丈高楼平地起,有时候我们太过追求一些高级语法,或者高大尚的东西,反而在基础的东西上掌握不牢,实际上,数据库的基础数据类型往往没有表面上看的那么简单,其实任何语言都是一样,只有掌握好基础知识,做一个基础精通者,那么,在我们进阶的道路上就会水到渠成。写到最后,才发现整体下来,整篇文章也没有那么轻松,严肃的东西写惯了,一下子不太适应写轻松的东西,没事,能抛砖引玉就好。
1、number
我最先接触的数值类型就是老大哥number,它定义为number(p,s),p是精度,最大38位,s是刻度范围,可在-84~127间取值。举个栗子(例子):number(4,2),指的就是小数点整数+小数部分一共有4位,不包含小数点位,也就是说整数部分最多两位,如果小数部分多于2位,会做四舍五入处理(对于sqlserver和mysql也会做四舍五入处理),如果小数部分不足2位的话,则会补0(对于sqlserver也会补0,但是mysql不会),如果不写p,s,那么就默认为38。number类型是oracle最常用的数字类型了,在很长一段时间之内,我以为数值类型就只有number,因为number类型足以处理几乎全部的数字类型了。但是之后在oracle道路上继续行走的过程中,我又认识了其他衍生的数值类型。
2、integer
其实最开始看到这个数值类型的时候,同很多人一样,我也认为它是number类型的子类型,最大38位,对于小数做自动四舍五入处理,但是后来我发现不完全是这样的。作为number的子类型不假,一般情况下,integer是作为存储整数值存在的,在需要存储整数值的时候我们会想到这个数值类型,但是它的最大位可不是38位,在插入的测试数值看到,它已经远远超过38位了,如图:
可以看到,对于integer只能存储38位的言论可谓是直接推翻。接下来我们来看坊间盛传的,"integer只能存储整数,对于小数会做四舍五入处理",来看一个例子:
create or replace procedure integer_test(a integer)
as
b integer := a;
begin
dbms_output.put_line(b);
end;
输出结果如图:
看到这个结果的时候,相信很多同学都已经凉了,简直是颠覆了以往的认识啊,的确,从这个例子可以看出,integer是number的子类型,但是它不会强制进行四舍五入处理,同时它最大位数大于38位。
3、int,numeric,decimal
这三种数值类型是oracle为了兼容其他数据库而存在的,同样都是number的子类型。在进行类型声明的时候,如果直接声明为int,numeric,decimal,它会被直接存为integer,处理方式同integer一模一样;numeric和decimal如果带有精度和刻度范围,那么会被存为number(p,s),处理方式同number(p,s),int类型只能被声明为int,不能带精度和刻度范围,所以只能当作integer来处理。
4、float
float也是number的子类型,float(n),n指的是精度,是二进制精度,这里可不是十进制精度哦,计算公式为:binary precision=ceil(b*0.30103),float没有刻度范围.n的范围为1~126。那么怎么计算存入数据库中的数值呢,比如:float(2),那么它的精度是ceil(2*0.30103)=1,如果存入13.5,那么应该是1.35*10^1,精度为1,1.35四舍五入变为1,所以就是1*10^1=10存入的结果就是10;如果是19.5,那么应该是1.95*10^1,精度为1,1.95四舍五入为2,就是2*10^1,结果存入20。如果没有精度,那么映射为number类型,直接存入此值。oracle没有直接为double类型的数值类型。
5、binary_integer和pls_integer
这个数字类型只能用于PL/SQL,他们相比number来说更具优势,首先是占有较少的存储空间,其次他们是直接通过硬件来计算的,也就是直接通过CPU进行计算,而不用经过转换,number类型在计算的时候,还要先被转换为二进制,所以在计算速度上,binary_integer和pls_integer比number性能好很多,建议在PL/SQL中使用这两种数据类型来代替number,你将会得到很大的惊喜。
5、binary_float和binary_double
这两种数值类型10g之后才出现,binary_float可以存储一个单精度的32位浮点数,binary_double可以存储一个双精度的64位浮点数,binary_float和binary_double占有更少的存储空间,同样的,binary_float和binary_double也是直接通过硬件计算的,所以它的计算效率更高,而且它们比起number来说可以存储更大或者更小的数值,但是这两种数值类型也会存在精度不准的情况。
6、写到浮点型,我需要说一说浮点型存数不精确的原因:
首先,我们要知道浮点型在计算机是怎么存储的,比如:要存入13.75,首先将整数部分转为二进制,13转为二进制是1101,接下来将小数部分转为二进制,小数部分是0.75,将小数部分乘以2,取结果的整数部分为二进制的一位,然后继续取结果的小数部分乘以2重复,一直到小数部分全部为0结束,在这个过程中,是会出现循环乘不尽的情况,但是因为浮点数的小数位是确定的(float是23位,double是52位),所以到了指定的小数位就会停下来,这就是浮点数存数不精确的原因,可以看到如果可以在小数位范围之内乘尽的话,那么结果就存储的准确了。来看看小数部分(0.75)转为二进制的过程:
0.75*2=1.5 取1
0.5*2=1 取1
乘到这里,即0.5*2=1,1已经没有小数部分了,所以到这里也就停止了,最后的结果是0.11,与上面整数部分合起来,那么13.75转换为二进制为1101.11,即1.10111*2^3,1.10111是小数部分,2为底,6为指数部分,这个1.10111*2^3就是转换好的二进制浮点数,接着就是将这个二进制浮点数存入计算机了。
将其存入计算机内,将会使用浮点表示法,分为三大部分:
第一部分:符号位,占用1位,用来区分正负数,0为正数,1为负数;对于1.10111*2^3,它是正数,所以符号位是0
第二部分:指数位,float占用8位,double占用11位,用来表示指数;对于1.10111*2^3,指数位是3
第三部分:小数位,float占用23位,double占用52位,用来表示小数,不足位数补0;对于1.10111*2^3,小数位是10111
所以对于float,符号位+指数位+小数位=1+8+23=32位,对于double,符号位+指数位+小数位=64位,同时可以看到,指数位决定了大小范围,小数位决定了精度。因为指数位有可能是正数,也有可能是负数,负数算起来比正数麻烦,所以为了减少计算的麻烦,在存储指数的时候,需要将它存储位无符号的整数,所以在指数位上会加一个偏移量,float的偏移量是127,double的偏移量是1023,如果需要转换为十进制的话,到时候指数减去相应的值就可以了。那么对于13.75(float),本来它的二进制指数值是3,现在就成了3+127=130,转换为二进制是10000010,最终:13.75(float)被存储为:符号位 指数位 小数位(不足位补0)=0 10000010 10111 00000 00000 00000 000
7、万丈高楼平地起,有时候我们太过追求一些高级语法,或者高大尚的东西,反而在基础的东西上掌握不牢,实际上,数据库的基础数据类型往往没有表面上看的那么简单,其实任何语言都是一样,只有掌握好基础知识,做一个基础精通者,那么,在我们进阶的道路上就会水到渠成。写到最后,才发现整体下来,整篇文章也没有那么轻松,严肃的东西写惯了,一下子不太适应写轻松的东西,没事,能抛砖引玉就好。
类型
小数
部分
数值
存储
精度
二进制
小数位
处理
就是
数位
结果
四舍五入
整数
范围
四舍
时候
点数
符号
指数
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
办公网络技术是什么
青岛移动软件开发工程师
网络安全部裴顺红
VB软件开发笔试题
专升本数据库技术知识点
我的世界永不关服的生存服务器
怎么把网页转到另一个服务器
广州工控软件开发哪家正规
广州安卓软件开发定制
软件开发生产率低
网络储存服务器设置
数据库作业定时执行
数据库主外键适用场景
2021年华东网络技术挑战赛
数据库入门培训提升班
亚马逊服务器主动扣款
服务器11051是什么端口
悟空日记软件开发
服务器管理阮家远程到期
神通数据库连接工具
系统软件开发邀标文件
怎么把网页转到另一个服务器
在数据库中可以存放
数据库表的数据同步
网络安全关于国家安全的事件
软件开发 项目开发与规划
杭州管理软件开发多少钱
软件开发培训广州
数据库的应用安全
买了一台服务器