在 SQL Server 中划分小数类型会导致不必要的尾随零
Posted
技术标签:
【中文标题】在 SQL Server 中划分小数类型会导致不必要的尾随零【英文标题】:dividing a decimal type in SQL Server results in unnecessary trailing zeros 【发布时间】:2015-01-18 16:26:21 【问题描述】:当我发现一些奇怪的行为时,我正在 SQL Server 中执行一些简单的财务计算。我试图将一串数字转换为十进制类型。虽然字符串不包含小数点,但根据我的规范,我知道字符串中的最后 3 个位置应该在小数点后面。
我的第一个方法有缺陷,但结果如下:
select convert(decimal(11,3),89456123/1000) as TotalUnits
这导致 89456.000。在强制转换之前执行除法会导致小数部分被截断。
所以我将除法操作移到演员表之外,如下所示:
select convert(decimal(11,3),89456123)/1000 as TotalUnits
这导致小数点后的位置激增。它返回 89456.12300000
根据我的十进制规范,我想要 11 位数字,其中 3 位在小数点后面。现在我总共有 13 位数字,小数点后有 8 位。发生了什么?
为了得到我想要的,我想我必须双重施法,像这样:
select convert(decimal(11,3), convert(decimal(11,3),89456123)/1000)
这给出了 89456.123。
事实证明,无论我除以什么,产生的小数点爆炸都是一样的。除法是将数据类型转换为双精度还是什么?
我的问题是: 为什么会发生这种情况,有没有更优雅的方法来弥补它,而不是双重转换为十进制。
编辑 我在 SO 上找到了这个 similar question,但看起来他们又是双重施法。
【问题讨论】:
这适用于 rme:select convert(decimal(11,3),89456123/1000.)
【参考方案1】:
SQL server 做整数运算,要强制它使用数字,你可以乘以 1.0
无需使用 convert 两次。这给出了 89456.123
没有双重转换。
select convert(decimal(11,3),89456123*1.0/1000) as TotalUnits
【讨论】:
答案是正确的,给了+1来平衡给-1的人。 在使用这种方法时,我还发现我可以只除以 1000.0 来触发数字结果。 @Slider345,是的,你是对的,需要一个数字字段来将结果转换为数字。【参考方案2】:为什么convert(decimal(11,3),89456123)/1000
以小数点后 6 位结尾?规则要求它。 numeric division has rather complicated rules about the resulting type.
当您说1.0
时,您最终会得到一个表示该值的比例因子最少的数字:
SELECT SQL_VARIANT_PROPERTY(1.11, 'BaseType')
SELECT SQL_VARIANT_PROPERTY(1.11, 'Precision')
SELECT SQL_VARIANT_PROPERTY(1.11, 'Scale')
SELECT SQL_VARIANT_PROPERTY(1.11, 'TotalBytes')
你应该怎么做?由于复杂的规则,我认为没有真正优雅的解决方案。我能想到的任何解决方案都涉及对中间结果的相当疯狂的类型推断。我推荐的解决方案与 RADAR 已经给出的解决方案几乎相同:
select convert(decimal(11,3), convert(decimal(11, 3), 89456123)/1000) as TotalUnits
主要区别在于我认为用作演员表简写的*1.0
“技巧”混淆了代码的含义。不过,如果您碰巧喜欢它,请随意使用它。
【讨论】:
这正是我想要弄清楚的——很好的解释,+1【参考方案3】:select convert(decimal(11,3),89456123/CONVERT(decimal(11,3),1000))
【讨论】:
虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。以上是关于在 SQL Server 中划分小数类型会导致不必要的尾随零的主要内容,如果未能解决你的问题,请参考以下文章