SQL Server中的数字,浮点数和小数之间的差异


322

numericfloatdecimal数据类型之间有何区别?在哪种情况下应使用哪种区别?

对于任何形式的金融交易(例如,薪水领域),首选哪种交易,为什么?


1
上面的小数和数字链接需要更新到docs.microsoft.com/zh-cn/sql/t-sql/data-types/…。上面的链接不再存在。
Nigel Ainscoe

1
通常,在处理财务主题时,使用除浮点数之外的Integer类型并将值存储为cents(而不是美元)是很有趣的。
Pedro

Answers:


493

仅当十进制(最多38位)提供的精度不足时才使用浮点实数数据类型

  • 近似数字数据类型不能存储为许多数字指定的确切值;他们存储的值非常接近。(Technet

  • 避免在WHERE子句搜索条件中使用浮点或实数列,尤其是=和<>运算符(Technet

因此通常来说,因为如果您的数字可以容纳,则十进制提供精度为[10E38〜38位数],并且较小的Float存储空间(可能还有速度)并不重要,处理异常行为和近似数值类型的问题也不重要可接受,通常使用Decimal

更有用的信息

  • 数字=十进制(5到17个字节)(精确的数字数据类型)
    • 将在.NET中映射为Decimal
    • 在SQL Server中都具有(18,0)作为默认(precision,scale)参数
    • scale =可以存储在小数点右边的最大小数位数。
    • 请注意,money(8字节)和smallmoney(4字节)也是精确的,并且映射到.NET中的Decimal并具有4个小数点(MSDN
    • 十进制和数字(Transact-SQL)-MSDN
  • 实数(4字节)(近似 数值数据类型)
  • 浮点数(8字节)(近似 数值数据类型)
    • 将在.NET中映射为Double
  • 无论使用哪种类型的处理器体系结构或数字的大小,所有精确的数字类型始终会产生相同的结果
  • 提供给float数据类型的参数定义了用于存储浮点数尾数的位数
  • 近似数值数据类型通常使用较少的存储空间并具有较好的速度(最高20倍),并且您还应考虑在.NET中转换它们的时间

确切的数值数据类型 近似数值数据类型

主要来源MCTS自定进度培训套件(考试70-433):Microsoft®SQLServer®2008数据库开发 -第3章-表,数据类型和声明性数据完整性第1课-选择数据类型(指南)-第93页


17
use the float or real data types only if the precision provided by decimal is insufficient-我认为实数少然后十进制是准确的,那么如果十进制不足,您怎么写才能使用实数?
BornToCode 2012年

7
真实精度较低,因此不建议使用此方法,除非需要存储大于十进制(> 10e38)的大数字或出于空间考虑。我想引号中的精度表示可能的值和大小,而不是精度
Iman 2012年

11
@BornToCode这里的“精度”是指您要存储的值的范围。如果您需要存储1e10到1e-10之间的值,那就decimal很好了。这是20的精度。如果您需要在1e20和1e-20之间存储值,那么decimal 就不能这样做。那是40位数的精度。您永远无法在同一decimal字段中存储1e20和1e-20 。相反,您可以使用float,将所有内容内部存储为2的对数。这可以在一个字段中提供所有范围的精度,但缺点是只有前8位数字才是准确的。
培根片

我第三次使用BornToCode和Iman的评论。我刚刚进行了实验(使用SQL Server 2012),似乎float(53)(精度最高的浮点类型)的机器epsilon是2.22044604925031E-16。因此,您将获得约15个有效数字。另一方面,我可以从十进制中得到38个有效数字。
斯图尔特

“使用float...”-说谁?这是报价还是您的意见?
user443854 '19

24

MSDN指南:使用十进制,浮点和实数据

数字和十进制数据类型的默认最大精度为38。在Transact-SQL中,数字在功能上等效于十进制数据类型。当必须完全按照指定的方式存储数据值时,请使用十进制数据类型存储带小数的数字。

float和real的行为遵循有关近似数字数据类型的IEEE 754规范。由于float和real数据类型的近似性质,因此在需要精确的数字行为时(例如,在金融应用程序中,涉及舍入的操作中或在相等性检查中),请勿使用这些数据类型。而是使用整数,十进制,货币或小货币数据类型。避免在WHERE子句搜索条件中使用浮点或实数列,尤其是=和<>运算符。最好将浮点数和实数列限制为>或<比较。


Scale列中指定(固定)小数位数。
Cees Timmerman 2014年

1
如果您希望“完全符合指定”,那么从标准的角度来看,它具有一定的优势,numeric因为它永远不会以比您要求的精度更高的精度存储:请参阅stackoverflow.com/a/759606/626804
Ed Avis

13

不是完整的答案,而是有用的链接:

“我经常针对十进制值进行计算。在某些情况下,在进行任何计算之前,将十进制值强制转换为ASAP浮点数会产生更好的精度。”

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/12/20/for-better-precision-cast-decimals-before-calculations.aspx


2
这没有道理。所有其他带有来源的答案都说数字或十进制数据类型是准确的,而浮点或实数类型则非常接近。由于精度较低,因此我可以理解,将浮标转换为浮点数可以加快计算速度,但不能提高精度。
cbaldan

3
所有数字数据类型都可能会发生上溢和下溢。上溢是一个显式错误,但是下溢是静默的。下溢为特色decimalfloat不同的。小数通过增加精度或小数位数来尽可能地防止下溢。但是,一旦达到十进制的有效位数限制,下溢将保持静音(并且精度会丢失)。浮点数可能具有更大范围的比例尺,而比例尺限制实际上是造成下溢的原因。因此,浮子可以具有更好的比例。但是,它仍然是不精确的类型。
ErikE

13

它们的数据类型优先级不同

十进制数字功能上相同,但仍然存在数据类型优先级,这在某些情况下可能至关重要。

SELECT SQL_VARIANT_PROPERTY(CAST(1 AS NUMERIC) + CAST(1 AS DECIMAL),'basetype')

产生的数据类型为数字,因为它优先于数据类型

按优先级列出数据类型的详尽列表:

参考链接


7

小数具有固定的精度,而浮点具有可变的精度。

编辑(无法阅读整个问题):Float(53)(又名实数)是SQL Server中的双精度(32位)浮点数。常规浮点数是单精度浮点数。对于许多计算而言,Double是精度和简单性的良好组合。您可以使用十进制创建一个非常高精度的数字(最大136位),但是还必须注意正确定义精度和小数位数,以便它可以将所有中间计算包含到所需的位数。


您没有指定在进行金融交易时哪个更可取,为什么?
priyanka.sarkar

对于SQL Server 2008和更高版本,float(53)aka float是双精度(64位)浮点数,而float(24)aka real是单精度(32位)浮点数。docs.microsoft.com/zh-cn/sql/t-sql/data-types/float-and-real-transact-sql
M Kloster,

4

浮点数是“近似数字”数据类型,这意味着不能准确表示该数据类型范围内的所有值。

十进制/数字是固定精度数据类型,这意味着可以使用精度和小数位数精确表示数据类型范围内的所有值。您可以使用十进制来省钱。

从十进制或数字转换为浮点数可能会导致精度损失。对于Decimal或Numeric数据类型,SQL Server将精度和小数位的每种特定组合视为不同的数据类型。DECIMAL(2,2)和DECIMAL(2,4)是不同的数据类型。这意味着11.22和11.2222是不同的类型,尽管float并非如此。对于FLOAT(6),11.22和11.2222是相同的数据类型。

您也可以使用money数据类型来省钱。这是本机数据类型,具有4位数的精度。大多数专家都喜欢使用这种数据类型来省钱。

参考 1 2 3


3

小数的情况

它的基本需求是什么?

它源于以下事实:计算机最终在内部以二进制格式表示数字。这不可避免地导致舍入错误。

考虑一下:

0.1 (decimal, or "base 10") = .00011001100110011... (binary, or "base 2")

上面的省略号表示“无限”。如果仔细看,会有无限的重复模式(='0011')

因此,在某些时候计算机必须舍入该值。这会导致由于重复使用不准确存储的数字而导致的累积错误。

假设您要存储财务金额(可能是小数的数字)。首先,您显然不能使用整数(整数没有小数部分)。从纯粹的数学观点来看,自然的趋势是使用float。但是,在计算机中,浮点数是位于小数点后的数字部分(“尾数”)的限制。这会导致舍入错误。

为克服此问题,计算机提供了特定的数据类型,这些数据类型限制了计算机中十进制数字的二进制舍入错误。这些是绝对应用于表示财务金额的数据类型。这些数据类型通常使用的名称Decimal。例如,在C#中就是这种情况。或者,DECIMAL在大多数数据库中。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.