从 varchar 转换为十进制而不会损失精度

Convert from varchar to decimal without precision loss

提问人:Narshe 提问时间:6/23/2020 最后编辑:Narshe 更新时间:6/24/2020 访问量:1144

问:

我正在使用一个表,其中包含小数存储为 VARCHAR 的数值数据。这些数字的小数点数量不可预测(我相信最多 10 位),但它们也可以采用科学记数法('1231E-03')

我一直在尝试不同的解决方法来处理它们(就像这里解释的那样 https://stackoverflow.com/a/18452603/5866637)

我在转换常规十进制数时没有问题,但是在处理指数表示法时,我无法摆脱浮点精度问题。

DECLARE @Value VARCHAR(MAX) = '123456789.123e-5'
SELECT CONVERT(Decimal(38,18), CONVERT(float, @Value))

将解析为

1234.567891229999986535

是否可以进行任何转换,以便我可以将上面的数字转换为小数

1234.567891230000000000

我试过将一堆零连接到数字上,但是当我必须进行投射才能浮动时,它会吃掉所有这些额外的零。

我尝试的另一件事是降低十进制值的精度。如果我使用,我会得到预期的值,但这会导致问题吗?如果我知道我永远不会在数据库中获得超过小数点 13 位的值,那么使用 convert to (38,13) 是否安全,或者我应该寻求不同的解决方法?Decimal(38,13)

如果这被认为是重复的,我们将不胜感激,但我发现的最接近的匹配是上面的链接,它是 6 年前制定的。

sql-server azure-sql-database 浮动精度

评论

0赞 Ilyes 6/23/2020
不可重现
1赞 Piotr Palka 6/23/2020
萨米语,在真正的 SQL Server 2017 上它是可重现的。
0赞 Narshe 6/24/2020
更具体地说,这是一个 Azure SQL 托管实例。更新了标签以澄清。很抱歉造成混乱
2赞 wqw 6/24/2020
在 SQL Server 2008 R2 上不可重置(返回)。请注意,在 SQL Server 2017 上,CONVERT to FLOAT 的返回也正确。这可能是 FLOAT 到 DECIMAL 转换的错误(或功能),因为比例高于 13,在 SQL Server 2017 上也按预期工作。1234.5678912300000000001234.56789123SELECT CONVERT(Decimal(38,13), CONVERT(float, @Value))
1赞 Alex 6/24/2020
我观察到与@wqw类似的行为:SQL Server 2014 Dev - 始终返回正确的值;SQL Server 2016 标准 - 大于 13 的规模会导致问题。

答:

3赞 Igor 6/23/2020 #1

您可以使用 ROUND

DECLARE @Value VARCHAR(MAX) = '123456789.123e-5'
SELECT round(CONVERT(Decimal(38,18), CONVERT(float, @Value)), 8)

评论

1赞 John Cappelletti 6/23/2020
好答案。奇怪的是,当你四舍五入到 14+ +1 时,它就会破裂
0赞 Narshe 6/23/2020
是否可以传递动态计算的四舍五入金额?您的解决方案适用于具有 8 位有效数字的数字,但如果它有超过 8 个相关数字?J.F. 它四舍五入为'123456789.123456789e-3'123456.789123460000000000
0赞 Igor 6/24/2020
你也许可以做一些数学运算来得到一个数字,并将其作为第二个参数传递给,但你为什么要在这一点上呢?我会根据您需要使用值的情况进行四舍五入或不四舍五入,而不是根据值本身做出决定。@Narsheround
0赞 Narshe 6/24/2020
我想避免四舍五入。我希望它可以像处理非 E 值一样工作,其中转换返回与文本上写的完全相同的数字。