SQL Server 小数类型(float 和 decimal)小数相除求占比为1的方法

在SQL Server中,实际上小数数值只有两种数据类型:float 和 decimal,分别是近似数值和精确数值。其他小数类型,都可以使用float和decimal来替代,例如,双精度(double precision)数据类型等价于 float(53),real等价于float(24),numeric是 decimal的同义词,应该避免在程序中直接使用 double precision、real和numeric,而是用 float(24) 、float(53)和decimal 代替。

float是近似数值,存在精度缺失;decimal是精确数值,不存在精度损失。当数值不允许精度丢失时,使用 decimal数据类型存储数据。在计算小数的除法时,SQL Server 内部隐式升级数据类型,根据小数数值的数据类型,就近向float(24) 或float(53)转换。

一,近似数值

float 表示近似数值,存在精度损失,数据类型是 float(n),n是可选的,默认类型是float(53),占用8bytes。虽然n的取值范围是1-53,实际上,float 只能表示两种类型float(53) 和 float(24),分别占用 8Bytes 和 4Bytes。

其中n是以科学计数法存储浮点数尾数的位数,因此决定了精度和存储大小。 如果指定了n,则它必须是介于1和53之间的值,n的缺省值是53。


n


Precision


Storage size


1-24    


7 digits


4 bytes


25-53  


15 digits


8 bytes

注意:SQL Server将n视为两个可能值之一。 如果1 <= n <= 24,则将n视为24;如果25 <= n <= 53,则将n视为53。

近似数值很难确定是否相等,因此,应避免对 float 类型做相等比较,而只限于比较 > 或 < 。

二,精确数值

decimal不存在精度损失,数据类型decimal(p,s) 需要分别指定小数的最大位数(p)和小数位的数量(s):

  • p (precision) :指定小数的最大位数,小数点的左侧和右侧的数字的总数量不能超过p,p的取值范围是从1到38,默认值为18。
  • s (scale):指定在小数点右侧的小数位数,p-s是小数点左边的最大位数。s必须是从0到p的值,只有在指定了精度的情况下才能指定s,s的默认值是0,因此,0 <= s <= p。

Precision


Storage bytes


1 - 9


5


10-19


9


20-28


13


29-38


17

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.

四,将小数转换成字符串(varchar)

相比cast(float_expression as float(24/53)),使用 str 函数能够有效控制近似数值的小数位数,函数str获取的是近视数值。

STR ( float_expression [ , length [ , decimal ] ] )
  • length是小数的总位数,包含正负符号,小数点,小数点左边和右边数字个数之和;
  • decimal是小数位的数量(小数点右边数字个数),小数位最大为16位,不能超过16,否则,会被截断为16位。如果小数位没有decimal多,那么右边补0。
  • 返回值是varchar类型。

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,返回的是近似值。

原文地址:https://www.cnblogs.com/yclizq/p/12264579.html

时间: 2024-10-25 13:10:52

SQL Server 小数类型(float 和 decimal)小数相除求占比为1的方法的相关文章

SQL Server 字段类型 decimal(18,6)小数点前是几位?记一次数据库SP的BUG处理

原文:SQL Server 字段类型 decimal(18,6)小数点前是几位?记一次数据库SP的BUG处理 SQL Server 字段类型 decimal(18,6)小数点前是几位? 不可否认,这是一个很低级的问题.... 为什么会问这么低级的问题? 由于这个问题,导致一个数据导入的SP执行失败....以至于困扰了我好几个小时.... 事情是这样的... 公司总部上了一套Oracle的ERP,我们系统中有些数据要从里面取,比如Supplier,Product等. Oracle会导出数据文件,我

SQL Server Datetime类型为NULL不能用ISNULL(datetime,&#39; &#39;)来判断,会导致1900-01-01

select top 10 --(case when zb.Order_CreatedOn is null then '' when zb.Order_CreatedOn<>'1900-01-01' then zb.Order_CreatedOn end) as Order_CreatedOn,*--datetime类型不能转成'',如果转成'',返回给程序就是1900-01-01,''这种空字符串默认就会返回1900-01-01,所以不用在SQL里面转换,在程序里面用DBNUll.value

浅析SQL SERVER执行计划中的各类怪相

在查看执行计划或调优过程中,执行计划里面有些现象总会让人有些疑惑不解: 1:为什么同一条SQL语句有时候会走索引查找,有时候SQL脚本又不走索引查找,反而走全表扫描? 2:同一条SQL语句,查询条件的取值不同,它的执行计划会一致吗? 3: 同一条SQL语句,其执行计划会变化,为什么 4: 在查询条件的某个或几个字段上创建了索引,执行计划就一定会走该索引吗? 5:同时存在几个索引,SQL语句会走那个索引? ..............................................

【转】SQL Server sql_variant 类型的比较

sql_variant 类型用于存储SQL SERVER中支持的各种数据类型. 为了进行 sql_variant 比较,SQL Server 数据类型层次结构顺序划分为多个数据类型系,sql_variant 数据类型在用于转换的数据类型层次结构列表中位于顶部. 数据类型层次结构 数据类型系列 sql_variant sql_variant datetime2 日期和时间 datetimeoffset 日期和时间 datetime 日期和时间 smalldatetime 日期和时间 date 日期

Sql Server xml 类型字段的增删改查

1.定义表结构 在MSSM中新建数据库表CommunicateItem,定义其中一个字段ItemContentXml 为xml类型 2.编辑表数据,新增一行,发现xml类型不能通过设计器录入数据. 需要写sql更新或插入. DECLARE @xml XML SET @xml=' <MyHobby> <MyCode>1</MyCode> <MyName>爬山</MyName> </MyHobby> <MyHobby> <

【转】SQL SERVER DateTime类型的精度

先看下边的SQL 语句 CREATE TABLE #DateTest( Id INT, SampleDate DATETIME ) INSERT INTO #DateTest VALUES(1,'1 jan 2010 10:30') INSERT INTO #DateTest VALUES(2,'2 jan 2010 23:59') INSERT INTO #DateTest VALUES(3,'3 jan 2010 12:34') INSERT INTO #DateTest VALUES(4,

sql server等待类型

等待的类型 资源等待 当某个工作线程请求访问某个不可用的资源(因为该资源正在由其他某个工作线程使用,或者该资源尚不可用)时,便会发生资源等待.资源等待的示例包括锁等待.闩锁等待.网络等待以及磁盘 I/O 等待.锁等待和闩锁等待是指等待同步对象 队列等待 当工作线程空闲,等待分配工作时便会发生队列等待.队列等待通常发生在系统后台任务(如监视死锁以及清除已删除的记录等任务)中.这些任务将等待工作请求被放入工作队列.即使没有新数据包放入队列,队列等待也可能定期处于活动状态. 外部等待 当 SQL Se

sql server Geometry 类型操作 笔记

IF OBJECT_ID ( 'dbo.SpatialTable', 'U' ) IS NOT NULL DROP TABLE dbo.SpatialTable;GO CREATE TABLE SpatialTable ( id int IDENTITY (1,1), GeomCol1 geometry, GeomCol2 AS GeomCol1.STAsText() );GO INSERT INTO SpatialTable (GeomCol1)VALUES (geometry::STGeom

[转载]C#中使用ADO.NET连接SQL Server数据库,自动增长字段用作主键,处理事务时的基本方法

问题描述: 假设在数据库中存在以下两张数据表: User表,存放用户的基本信息,基本结构如下所示:   类型 说明 ID_User int 自动增长字段,用作该表的主键 UserName varchar   UserDepart表,存放用户所拥有的部门(我们假设一个用户拥有多个部门,虽然听起来有点别扭,此处仅作示例,可以理解为一个用户拥有多个职位等等),该表的基本结构如下所示:   类型 说明 ID_UserDepart int 自动增长字段,用作该表的主键 ID_User int 用户编号 I