为什么在此COALESCE语句中发生这种隐式类型转换?

时间:2019-04-26 19:58:34

标签: sql-server database types sqldatatypes

为什么Ceiling()在这里将数据类型更改为(38,0),在小数点后失去精度?

这仅在Decimal(38,X)下发生,如下所示。

在Microsoft SQL Server 2016上运行

DECLARE @decimal2 DECIMAL(37,4) = 1.1
SELECT COALESCE(1.1,CEILING(@decimal2)) 

^这将返回1.1

DECLARE @decimal DECIMAL(38,4) = 1.1
SELECT COALESCE(1.1,CEILING(@decimal))

^这将返回1 !!

3 个答案:

答案 0 :(得分:3)

Ceiling返回一个整数,但是它应该是传入的数据类型。我不知道为什么在示例中导致了此特定问题,但是您可以像这样克服它:

DECLARE @decimal DECIMAL(38,4) = 1.1
SELECT COALESCE(@decimal,CEILING(@decimal)) --RETURNS 1
SELECT COALESCE(@decimal,CAST(CEILING(@decimal) AS DECIMAL(38,4))) --RETURNS 1.1000

我避免此类问题的规则是始终将不同的数据类型转换为通用的数据类型。

答案 1 :(得分:0)

({混淆})Microsoft Docs的Precision, scale, and Length (Transact-SQL)文章对此行为进行了解释。 这是文章的摘录:

  

结果精度和小数位数的绝对最大值为38。当结果精度大于38时,它将减小为38,并减小相应的小数位数,以防止截断结果的整数部分。

现在,令人困惑的部分是要了解如何计算精度和小数位数。从我的测试来看,它似乎正在使用加法规则。对于精度max(s1, s2) + max(p1-s1, p2-s2) + 1和比例max(s1, s2)。但是由于精度超过38,所以从比例尺上取了差值,以保持整体零件的完整性。

答案 2 :(得分:0)

这仅仅是由于以下事实:数字数据类型只能容纳38位数字,并且将首先填充最高有效值,因此,如果您说37,4,它将填充小数点左侧的37位并保留剩下的一个在右边。 如果您在小数点左边加38,则无论您在右边加什么,都没有小数位。