5

在所有其他语言(通常是算术引擎)中,在相同优先级的运算符周围放置一组额外的括号不会影响结果。但最近在一个测试项目中,我注意到 MS SQL 服务器在这些情况下改变了结果。请查看下面的查询,如果您有任何想法(或 SQL Server 管理中的设置)或任何指向 MSDN 文章的链接来解释该行为,请告诉我。

select (0.55 * 287.61 / 0.66) calc_no_parens
,(0.55 * (287.61 / 0.66)) calc_parens
,round(0.55 * 287.61 / 0.66,2) no_paren_round
,round(0.55 * (287.61 / 0.66),2) paren_round;

结果

Column  Record 1
calc_no_parens  239.6750000
calc_parens     239.67499985
no_paren_round  239.6800000
paren_round     239.67000000

对我来说,他们中的前两个应该返回 239.675,回合应该返回 239.68。

4

4 回答 4

4

如果您将每个值声明为 ,您将获得所需的结果Float

DECLARE @Float1 float, @Float2 float, @Float3 float;
SET @Float1 = 0.55;
SET @Float2 = 287.61;
SET @Float3 = 0.66;

select (@Float1 * @Float2 / @Float3) calc_no_parens
,(@Float1* (@Float2/ @Float3)) calc_parens
,round(@Float1 * @Float2/ @Float3,2) no_paren_round
,round(@Float1* (@Float2/ @Float3),2) paren_round;

输出

calc_no_parens  calc_parens no_paren_round  paren_round
239.675          239.675    239.68           239.68

您可能想看这篇文章:所谓的“精确”数字根本不精确!

于 2012-09-17T04:35:45.003 回答
3

我可以看到正在发生的事情,但我认为没有解决办法。

SQL 将函数的每个部分计算并存储为 SQL 数据类型(在本例中为浮点数)。

287.61/0.66 产生 435.7727272727272727272727272... SQL 将存储为浮点数以达到一定程度的准确性,但它并不准确(毕竟,它是一个浮点数)。

有关浮点数的更多信息:浮点数是如何存储的?什么时候重要?

于 2012-09-17T04:36:21.363 回答
0

Habib 的回答让我认为这必须是我的列使用的十进制数据类型。经过一番研究,我发现了这个 Precision, Scale, and Length (Transact-SQL)

正如您在那篇文章中看到的那样,除法运算显着改变了结果小数的比例和精度。然后我尝试了我的查询的变体,这次在乘法运算周围添加了额外的括号。

select distinct (0.55 * 287.61 / 0.66) calc_no_parens
,(0.55 * (287.61 / 0.66)) calc_parens_div
,((0.55 * 287.61) / 0.66) calc_parens_mult
,round(0.55 * 287.61 / 0.66,2) no_paren_round
,round(0.55 * (287.61 / 0.66),2) paren_round
,round((0.55 * 287.61) / 0.66,2) paren_round2;

结果

Column              Record 1
calc_no_parens      239.6750000
calc_parens_div     239.67499985
calc_parens_mult    239.6750000
no_paren_round      239.6800000
paren_round         239.67000000
paren_round2        239.6800000

因此,只要除法是公式中的最后一个运算符,我们就会得到正确的答案。它不是解决问题的方法,而是在任何未来的测试项目中学习自我。

于 2012-09-17T15:57:35.407 回答
0

当您使用数字 SQL 尝试动态转换它们:

{

SELECT 
0.55*(287.61 / 0.66) PrecisionError, 
0.55* (CONVERT(NUMERIC(24,12), 287.61) / CONVERT(NUMERIC(24,12), 0.66)) NotPrecisionError

DECLARE @V SQL_VARIANT
SET @V = 0.55*(287.61 / 0.66)

SELECT 
Value = @V
,[TYPE] = CONVERT(SYSNAME, sql_variant_property(@V, 'BaseType')) + '(' + 
          CONVERT(VARCHAR(10), sql_variant_property(@V, 'Precision')) + ',' + 
          CONVERT(VARCHAR(10), sql_variant_property(@V, 'Scale')) + ')'  

SET @V = 0.55 * (CONVERT(NUMERIC(24,14), 287.61) / CONVERT(NUMERIC(24,14), 0.66))
SELECT 
Value = @V
,[TYPE] = CONVERT(SYSNAME, sql_variant_property(@V, 'BaseType')) + '(' + 
          CONVERT(VARCHAR(10), sql_variant_property(@V, 'Precision')) + ',' + 
          CONVERT(VARCHAR(10), sql_variant_property(@V, 'Scale')) + ')'

}

结果

PrecisionError NotPrecisionError

239.67499985 239.6750000000000

价值 类型

239.67499985 数字(14,8)

价值 类型

239.6750000000000 数字(38,13)

于 2014-07-06T03:51:53.250 回答