在SQL中将值从实值列复制到十进制值列

时间:2014-08-05 03:46:52

标签: sql sql-server

在我们的一个SQL表中,我们有一个真实的字段。实际精度为7.我们的应用需要更高的精度。所以我们决定将真实字段转换为十进制字段。

由于我们的表非常大,而且因为我们无法关闭事务日志,所以我们决定使用以下方法。

  • 将实际列重命名为real_value_old(以前的名称为real_value)
  • 创建名为real_value且数据类型为decimal的新实列(38, 8)
  • 批量复制值从real_value_old到real_value

我们正面临着这种方法的一些问题。 例如,如果real_value_old为545370.2,则real_value设置为545370.18750000

当我们检查问题时,我们认为是因为以下问题

update table set real_value = cast (real_value_old as decimal(38,8)) where some_condition
update table set real_value = ROUND(cast (real_value_old as decimal(38,8)), 8) where some_condition
update table set real_value = convert (decimal(38,8), real_value_old, 38) where some_condition
update table set real_value = real_value_old  where some_condition

在以上所有情况中, 如果real_value_old为545370.2,则real_value设置为545370.18750000

有人可以在这提供解决方案吗?

此代码可以快速准确显示问题所在。在sql server 2012上确认

DECLARE @real REAL = 545370.2
SELECT cast(@real AS DECIMAL(38, 8))
    ,ROUND(cast(@real AS DECIMAL(38, 8)), 8)
    ,convert(DECIMAL(38, 8), @real, 38)

2 个答案:

答案 0 :(得分:1)

以下链接将给出函数以获取浮点数据类型的位数

How to get the count of digits after the decimal point in a float column in ms sql?

修改该函数以在函数参数中使用REAL 然后,下面的SQL将工作

update table set real_value = ROUND(CAST (real_value_old AS decimal (38,8)), dbo.countDigits(real_value_old)) where some_condition

完整代码如下:

CREATE FUNCTION dbo.countDigits(@A real) RETURNS tinyint AS
BEGIN
declare @R tinyint
IF @A IS NULL 
   RETURN NULL
set @R = 0
while @A - str(@A, 18 + @R, @r) <> 0
begin
   SET @R = @R + 1
end
RETURN @R
END
GO

DECLARE @real REAL = 545370.2
SELECT ROUND( cast(@real AS DECIMAL(38, 8)), dbo.countDigits(@real))

答案 1 :(得分:0)

MSDN文档中REAL数据类型的定义:

用于浮点数字数据的近似数字数据类型。浮点数据是近似值;因此,并非数据类型范围中的所有值都可以准确表示。 real的ISO同义词是float(24)。

这个例子展示了这在现实世界中是如何运作的(双关语)

DECLARE @real REAL = 545370.2
SELECT cast(@real AS DECIMAL(38, 8))
    ,ROUND(cast(@real AS DECIMAL(38, 8)), 8)
    ,convert(DECIMAL(38, 8), @real, 38)

每个结果都在545370.18750000

 DECLARE @float float(24) = 545370.2
SELECT cast(@float AS DECIMAL(38, 8))
    ,ROUND(cast(@float AS DECIMAL(38, 8)), 8)
    ,convert(DECIMAL(38, 8), @float, 38)

与第一个块相同

 DECLARE @doublefloat float(53) = 545370.2
SELECT cast(@doublefloat AS DECIMAL(38, 8))
    ,ROUND(cast(@doublefloat AS DECIMAL(38, 8)), 8)
    ,convert(DECIMAL(38, 8), @doublefloat, 38)

双精度浮点数正确:545370.20000000

所以你去吧。当结果不允许进行近似并且研究您的数据类型以避免头痛时,不要使用近似数字;)

修改 示例中给出的具体数字可以这样处理:

DECLARE @float real = 545370.2
SELECT CEILING(@float*10)/10

根据您所处理的数字范围,您可以使用适用于整个范围的CEILING / FLOOR / ROUND来查看公式。