【问题标题】:SQL Server 2008: Error converting data type nvarchar to floatSQL Server 2008:将数据类型 nvarchar 转换为浮点数时出错
【发布时间】:2012-02-26 13:08:10
【问题描述】:

目前正在解决运行此 SQL 查询的问题:

UPDATE tblBenchmarkData 
SET OriginalValue = DataValue, OriginalUnitID = DataUnitID, 
    DataValue = CAST(DataValue AS float) * 1.335 
WHERE 
    FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5' 
    AND ZEGCodeID IN 
             (SELECT ZEGCodeID FROM tblZEGCode 
              WHERE(ZEGCode = 'C004') OR 
                   (LEFT(ZEGParentCode, 4) = 'C004'))

导致以下错误:

消息 8114,第 16 级,状态 5,第 1 行
将数据类型 nvarchar 转换为浮点数时出错。

真正奇怪的是,如果我将 UPDATE 更改为 SELECT 以检查检索到的值是数值:

SELECT DataValue 
FROM tblBenchmarkData 
WHERE FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5' 
AND ZEGCodeID IN 
         (SELECT ZEGCodeID 
          FROM tblZEGCode WHERE(ZEGCode = 'C004') OR 
                               (LEFT(ZEGParentCode, 4) = 'C004'))

结果如下:

DataValue
2285260
1205310

想使用TRY_PARSE 或类似的东西;但是,我们在 SQL Server 2008 而不是 SQL Server 2012 上运行。有人有什么建议吗? TIA。

【问题讨论】:

    标签: sql-server-2008 casting floating-point nvarchar


    【解决方案1】:

    执行顺序并不总是符合预期。

    如果您设置了where 子句,这通常并不意味着select 列表中的计算只会应用于与where 匹配的行。 SQL Server 可能很容易决定进行批量计算,然后过滤掉不需要的行。

    也就是说,您可以轻松地自己编写 try_parse:

    create function dbo.try_parse(@v nvarchar(30))
    returns float
    with schemabinding, returns null on null input
    as
    begin
      if isnumeric(@v) = 1
        return cast(@v as float);
    
      return null;
    end;
    

    【讨论】:

      【解决方案2】:

      查看 tblBenchmarkData 的架构定义会很有帮助,但您可以尝试在查询中使用 ISNUMERIC。比如:

      SET DataValue = CASE WHEN ISNUMERIC(DataValue)=1 THEN CAST(DataValue AS float) * 1.335 
                           ELSE 0 END
      

      【讨论】:

        【解决方案3】:

        所以从你的更新查询开始,它给出了一个错误(请原谅我为了我自己的清楚而重写它):

        UPDATE B
        SET
           OriginalValue = DataValue,
           OriginalUnitID = DataUnitID,
           DataValue = CAST(DataValue AS float) * 1.335
        FROM
           dbo.tblBenchmarkData B
           INNER JOIN dbo.tblZEGCode Z
              ON B.ZEGCodeID = Z.ZEGCodeID
        WHERE
           B.FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
           AND (
              Z.ZEGCode = 'C004' OR 
              Z.ZEGParentCode LIKE 'C004%'
           )
        

        我想你会发现带有完全相同表达式的 SELECT 语句会给出同样的错误:

        SELECT
           OriginalValue,
           DataValue NewOriginalValue,
           OriginalUnitID,
           DataUnitID OriginalUnitID,
           DataValue,
           CAST(DataValue AS float) * 1.335 NewDataValue
        FROM
           dbo.tblBenchmarkData B
           INNER JOIN dbo.tblZEGCode Z
              ON B.ZEGCodeID = Z.ZEGCodeID
        WHERE
           B.FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
           AND (
              Z.ZEGCode = 'C004' OR 
              Z.ZEGParentCode LIKE 'C004%'
           )
        

        这应该会显示无法转换的行:

        SELECT
            B.*
         FROM
            dbo.tblBenchmarkData B
            INNER JOIN dbo.tblZEGCode Z
               ON B.ZEGCodeID = Z.ZEGCodeID
         WHERE
            B.FieldDataSetID = '6956beeb-a1e7-47f2-96db-0044746ad6d5'
            AND (
               Z.ZEGCode = 'C004' OR 
               Z.ZEGParentCode LIKE 'C004%'
            )
            AND IsNumeric(DataValue) = 0
            -- AND IsNumeric(DataValue + 'E0') = 0 -- try this if the prior doesn't work
        

        最后一行注释的技巧是在字符串上附加一些东西,以强制只有有效数字为数字。例如,如果您只想要整数,IsNumeric(DataValue + '.0E0') = 0 会显示那些不是的。

        【讨论】:

        • 感谢您的反馈!我还遇到的一个问题是,如果数据采用科学计数法,CAST 就不起作用。因此,要解决该问题,请执行将所有数字从科学记数法更改为标准记数法的数据库视图,例如 DataValue 2.86777e+006 5.43724e+006
        • 啊哈,如果你真的已经有了科学记数法,那么我添加“E0”的技巧就行不通了。但是 IsNumeric 函数应该仍然可以为您提供帮助。
        猜你喜欢
        • 2017-03-23
        • 2017-03-15
        • 1970-01-01
        • 2021-08-08
        • 1970-01-01
        • 1970-01-01
        • 2011-05-18
        • 1970-01-01
        相关资源
        最近更新 更多