在SQL Server中,实际上小数数值只有两种数据类型:float 和 decimal,分别是近似数值和精确数值。其余小数类型,均可以使用float和decimal来替代,例如,双精度(double precision)数据类型等价于 float(53),real等价于float(24),numeric是 decimal的同义词,应该避免在程序中直接使用 double precision、real和numeric,而是用 float(24) 、float(53)和decimal 代替。html
float是近似数值,存在精度缺失;decimal是精确数值,不存在精度损失。当数值不容许精度丢失时,使用 decimal数据类型存储数据。在计算小数的除法时,SQL Server 内部隐式升级数据类型,根据小数数值的数据类型,就近向float(24) 或float(53)转换。git
float 表示近似数值,存在精度损失,数据类型是 float(n),n是可选的,默认类型是float(53),占用8bytes。虽然n的取值范围是1-53,实际上,float 只能表示两种类型float(53) 和 float(24),分别占用 8Bytes 和 4Bytes。express
其中n是以科学计数法存储浮点数尾数的位数,所以决定了精度和存储大小。 若是指定了n,则它必须是介于1和53之间的值,n的缺省值是53。app
decimal不存在精度损失,数据类型decimal(p,s) 须要分别指定小数的最大位数(p)和小数位的数量(s):
p 和 s 必须遵照规则:0 <= s <= p <= 38,decimal(p,s) 可以表示的有效值是从 - 10^38 +1 到 10^38 - 1。
decimal 数据类型的最大精度为 38,这意味着,decimal 数据类型最多能够存储 38位数字,全部这些数字都可位于小数点后面。decimal 数据类型存储精确的数字表示形式,没有近似值。
小数的除法是近似计算,必须把小数的类型提高为float类型。小数常量的默认数据类型是decimal,float的优先级比decimal高。
在Transact-SQL语句中,具备小数点的常量会自动转换为decimal,并使用必需的最小精度和小数位数。 例如,将常量12.345转换为小数类型,decimal(5,3),即精度为5,小数位为3。
在TSQL中,小数常量是decimal类型,如一下示例,TSQL把常量 1.0 自动转换为decimal(2,1),在计算除法时,TSQL自动把decimal转换位float类型。
declare @f_low float(24) declare @f_high float(53) select @f_low=cast(1.0 as float(24))/3,@f_high=cast(1.0 as float(53))/3 select 1.0/3 as f,@f_low as f_low, @f_high as f_high
declare @dec decimal(38,37) declare @num decimal(38,37) select @dec=cast(1.0 as decimal(38,37))/3,@num=cast(1.0 as decimal(38,37)) select @dec,@num,1.0/3,cast(1.0 as float(24))/3,1.000000000000/3,cast(1.0 as float(53))/3
默认状况下,SQL Server将小数常量做为decimal 数据类型,在计算小数的除法时,就近进行数据类型的升级,转换为float(24)或float(53) 数据类型。
在 Transact-SQL 语句中,小数数值的常量自动转换为 decimal 数据类型,在转换时,使用最小的精度和小数位数。例如,常量 12.345 被转换为 numeric 值,其精度为 5,小数位为 3。
In Transact-SQL statements, a constant with a decimal point is automatically converted into a numeric data value, using the minimum precision and scale necessary. For example, the constant 12.345 is converted into a numeric value with a precision of 5 and a scale of 3.
相比cast(float_expression as float(24/53)),使用 str 函数可以有效控制近似数值的小数位数,函数str获取的是近视数值。
STR ( float_expression [ , length [ , decimal ] ] )
1,对小数常量转换为varchar类型,减小小数位的数量,由2位减小为1位。
SELECT STR(123.45, 6, 1);
2,将decimal 变量转换为varchar类型
declare @d decimal(10,2) set @d=123.45 SELECT STR(@d, 6, 1);
3,将 float 表达式的值转换为varchar 类型
1.0/3 默认转换为float(24) 类型,所以只有6位小数,小于decimal 参数的8位,右边补两个0。
SELECT STR(1.0/3, 10, 8);
4,在将float和decimal转换为varchar类型时,使用函数str或cast强制转换,返回的数值多是不相同
declare @dt decimal(38,30) declare @df float(53) set @dt=50.8863983154297 set @df=50.8863983154297 select @df as df,@dt as dt, str(@dt,38,30) as str_dt,str(@df,38,30) as str_df, cast(@dt as varchar(100)) as var_dt,cast(@df as varchar(100)) as var_df
字段str_dt和str_df的值是不相同的,str函数首先对这两个小数数值取近似值,使用cast强制转换,对于decimal,返回的是精确值,对于float,返回的是近似值。