我需要在SQL Server中将Float转换为Decimal(28,10)。我的问题是由于浮动的性质以及转换的方式,简单地转换浮动可能会使我的用户显示错误的数字。
例如:
Float: 280712929.22
Cast as Decimal: 280712929.2200000300
What I think I want: 280712929.2200000000
我对float的工作原理(它是一种近似的数据类型等)有所了解,但不足以理解为什么它最后添加了300。它只是垃圾作为转换的副作用,还是以某种方式更精确地表示浮动实际存储的内容?对我来说,看起来它是凭空而来的精确度。
最终,我需要它是准确的,但也要看起来“正确”。我想我需要得到那个底部数字,因为它看起来我刚刚添加了尾随零。这可能吗?这是一个好主意还是坏主意,为什么?欢迎提出其他建议。
其他一些例子:
Float: 364322379.5731
Cast as Decimal: 364322379.5730999700
What I want: 364322379.5731000000
Float: 10482308902
Cast as Decimal: 10482308901.9999640000
What I want: 10482308902.0000000000
附注:我将这些值放入的新数据库表是我的用户可读的。它们实际上现在只需要两个小数位,但是将来可能会改变,所以我们决定使用Decimal(28,10)。长期目标是将我获取数据的浮点数转换为小数。
编辑:有时我拥有的浮点数比我需要的更多小数位,例如:-0.628475064730907。在这种情况下,施法到-0.6284750647就好了。我基本上需要将结果添加到浮点的末尾,直到我有10个小数位。
答案 0 :(得分:8)
你需要施放一次到圆形,然后再添加一次小数位(还有其他方法,当然,使用STR
,ROUND
等):
DECLARE @c TABLE(x FLOAT);
INSERT @c SELECT 280712929.22;
INSERT @c SELECT 364322379.5731;
INSERT @c SELECT 10482308902;
SELECT x,
d = CONVERT(DECIMAL(28,10), x),
rd = CONVERT(DECIMAL(28,10), CONVERT(DECIMAL(28,4), x))
FROM @c;
结果:
x d rd
-------------- ---------------------- ----------------------
280712929.22 280712929.2200000300 280712929.2200000000
364322379.5731 364322379.5730999700 364322379.5731000000
10482308902 10482308902.0000000000 10482308902.0000000000
如果您希望它准确并且看起来正确,请停止使用FLOAT
,这是一种近似数据类型,并且违反了严格数学背景之外的大多数人的逻辑。使用比您需要的更大的DECIMAL
,并将其格式化为您现在需要的小数位数(在查询中,或创建视图,或创建计算列)。如果您存储的信息超出了现在的需求,您可以随时公开更多信息。您也可以选择不让用户直接访问您的表格。
答案 1 :(得分:1)
当我需要将大数据表从float转换为十进制(28,15)时,遇到了这个问题。 正如@Dan答案的注释中指定的那样,对于某些值,他的答案无法正常工作。
这是我用来进行更新的最终版本
DECLARE @myTable TABLE(x FLOAT);
INSERT INTO @myTable VALUES
(280712929.22),
(364322379.5731),
(10482308902),
(-0.628475064730907),
(-0.62847506473090752665448522),
(8.828),
(8.9),
(8.999),
(8),
(9),
(0.000222060864421707),
(5.43472210425371E-323),
(1.73328282953587E+81);
SELECT x,
d = CONVERT(DECIMAL(28,15), ROUND( CONVERT(DECIMAL(28,15),
CONVERT(DECIMAL(16,15),
LEFT(CONVERT(VARCHAR(50), x, 2),17))
* POWER(CONVERT(DECIMAL(38,19),10),
CASE
WHEN RIGHT(CONVERT(varchar(50), x,2),4) > 12 THEN 12
ELSE RIGHT(CONVERT(varchar(50), x,2),4)
END)), 14 )),
SimpleVarchar = TRY_CONVERT(VARCHAR(50), x),
AnsiVarchar = TRY_CONVERT(VARCHAR(50), x, 2)
FROM @myTable;
我舍弃了很小的精度,因为我舍入了小数点后14位。但是在我的情况下,这是可以接受的。