代码之家  ›  专栏  ›  技术社区  ›  VVS

SQL Server:使用数字文本进行计算

  •  9
  • VVS  · 技术社区  · 15 年前

    我用浮点运算做了一些测试,以最小化精度损失。我偶然发现了一个我想在这里展示的现象,希望能得到一个解释。

    当我写作的时候

    print 1.0 / (1.0 / 60.0)
    

    结果是

    60.0024000960
    

    当我编写相同的公式并对 float

    print cast(1.0 as float) / (cast(1.0 as float) / cast(60.0 as float))
    

    结果是

    60
    

    到目前为止,我认为带小数点的数字文本自动被视为 浮动 具有适当精度的值。铸造到 real 显示与强制转换相同的结果 浮动 .

    • 是否有一些关于SQL Server如何评估数字文本的文档?
    • 这些文本属于什么数据类型?
    • 我真的要把它们扔给 浮动 提高精度(这听起来很讽刺:)?
    • 有没有比把我的公式和石膏混在一起更容易的方法?
    4 回复  |  直到 6 年前
        1
  •  9
  •   Lieven Keersmaekers    15 年前

    SQL Server使用尽可能小的数据类型。

    运行此脚本时

    SELECT SQL_VARIANT_PROPERTY(1.0, 'BaseType')
    SELECT SQL_VARIANT_PROPERTY(1.0, 'Precision')
    SELECT SQL_VARIANT_PROPERTY(1.0, 'Scale')
    SELECT SQL_VARIANT_PROPERTY(1.0, 'TotalBytes')
    

    您将看到SQL Server隐式地使用了数字(2,1)数据类型。
    除以60.0将结果转换为数字(8,6)。
    最终计算将结果转换为数字(17,10)。


    编辑

    从SQL Server联机丛书中获取 Data Type Conversion

    在Transact-SQL语句中,常量 带小数点的自动 转换为数字数据值, 使用最小精度和刻度 必要的。例如,常数 12.345转换为精度为5和A的数值 规模3。

        2
  •  4
  •   A-K    15 年前

    是的,您经常需要对它们进行铸造以获得更好的精度。我的看法是:

    For better precision cast decimals before calculations

        3
  •  3
  •   f470071    9 年前

    我认为应该理解幕后发生的事情,以便在类似情况下将来参考。

    带小数点(不包括科学记数法)的文字数字值表示十进制数据类型,该数据类型存储为尽可能小的十进制类型。与Lieven Keersmaekers的报价相同: https://msdn.microsoft.com/en-us/library/ms191530%28SQL.90%29.aspx#_decimal

    在Transact-SQL语句中,带小数点的常量是 使用最小值自动转换为数字数据值 精度和比例是必要的。例如,常数12.345是 转换为精度为5、小数位数为3的数值。

    小数点右边的尾随零指定小数位数。小数点左边的前导零将被忽略。

    一些例子:

    1.0  -> Decimal(2,1)
    60.0 -> Decimal(3,1)
    1.00 -> Decimal(3,2)
    01.0 -> Decimal (2,1)
    

    另一个需要考虑的问题是 Data Type precedence . 当一个运算符组合两个不同数据类型的表达式时,数据类型优先级规则指定将优先级较低的数据类型转换为优先级较高的数据类型。 还有一个需要考虑的问题是,如果我们对十进制类型进行算术运算,那么得到的十进制类型,即精度和小数位数都依赖于操作数和运算本身。文档中对此进行了描述 Precision, Scale, and Length .

    所以,你的表达式的一部分在括号里

    ( 1.0 / 60.0 ) is evaluated to 0.016666 and the resulting type is Decimal (8,6)
    

    使用上面关于十进制表达式的精度和小数位数的规则。此外,还使用银行的四舍五入或四舍五入为偶数。需要注意的是,使用的小数和浮点类型的舍入不同。 如果我们继续表达

    1.0 / 0.016666 is evaluated to 60.002400096 and the resulting type is Decimal (17,10)
    

    因此,这种差异的部分原因是小数类型的舍入与浮点类型的舍入不同。

    根据上述规则,只使用一个内圆括号就足够了。根据数据类型优先规则,其他所有文字都将提升为浮动。

    1.0 / (1.0 / cast(60.0 as float))
    

    还有一件更重要的事。即使这个float表达式也不能计算精确的结果。正因为如此,前端(SSMS或其他)将值舍入到(我猜)精度6位,然后截断尾随的零。因此,即1.000001变为1。

    很简单,不是吗?

        4
  •  0
  •   20yco    6 年前

    要编写常量浮点表达式,请尝试使用科学记数法:

    select (1.0E0 / (1.0E0 / 60.0E0))

    结果是60。