SQL Server 2008:将数据类型nvarchar转换为float时出错

时间:2012-02-03 23:07:50

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

目前正在解决运行此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'))

导致以下错误:

  

Msg 8114,Level 16,State 5,Line 1
  将数据类型nvarchar转换为float时出错。

真奇怪的是,如果我将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。

3 个答案:

答案 0 :(得分:5)

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

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

答案 1 :(得分:2)

执行顺序并不总是符合一个人的期望。

如果设置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 :(得分:1)

首先从您的更新查询开始,这是一个错误(请原谅我为了我自己的清晰度重写它):

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会显示那些不是整数。