【问题标题】:SQL IsNumeric Returns True but SQL Reports 'Conversion Failed'SQL IsNumeric 返回 True 但 SQL 报告“转换失败”
【发布时间】:2009-02-20 15:48:44
【问题描述】:

假设以下数据:

Column1 (data type: varchar(50))
--------
11.6
-1
1,000
10"    
Non-Numeric String

我有一个查询,它正在从该列中提取数据,并想确定该值是否为数字,然后在我的查询中返回它。所以我正在做以下事情

SELECT CASE
       WHEN IsNumeric(Replace(Column1, '"', '')) = 1 THEN Replace(Column1, '"', '')
       ELSE 0
   END AS NumericValue

SQL 正在报告:

将 varchar 值“11.6”转换为数据类型 int 时转换失败。

为什么?我也尝试过强制转换:

SELECT CASE
       WHEN IsNumeric(Replace(Column1, '"', '')) = 1 THEN cast(Replace(Column1, '"', '') AS float)
       ELSE 0
   END AS NumericValue

我得到了:

将数据类型 varchar 转换为 float 时出错。

【问题讨论】:

  • IsNumeric() 将接受双精度/浮点/单精度等。此外,它不检查溢出(99999999999999999999999999999 是数字,不会转换为大多数数字类型)。这种情况的最佳做法是,您首先不要将数字数据存储在字符串字段中

标签: sql sql-server tsql


【解决方案1】:

你需要用句号替换逗号:

CAST(REPLACE(column, ',', '.') AS FLOAT)

SQL Server 输出使用语言环境定义的小数分隔符,但除了CASTs 中的句点以外,什么都不理解为数字类型。

【讨论】:

  • 这行得通。我想我正在寻找一些过于复杂的东西来涵盖这种情况。谢谢。
  • 不,我完全删除了逗号。
  • 在某些语言环境中(例如我的),“1,000”是 1。“千”将是“1 000,00”。
  • FormView绑定元素怎么办?
  • @samir105:怎么办?什么是表单视图?什么是绑定元素?
【解决方案2】:

首先将字符串转换为货币,然后将其转换为任何其他数字格式,因为货币类型总是给出真正的数字字符串。这样你就永远不会看到错误了。

在您的查询中尝试以下内容,您就会知道我在说什么。两者都将返回 2345.5656。 Money 数据类型四舍五入到小数点后 4 位,因此转换导致四舍五入到小数点后 4 位。

SELECT CAST('2,345.56556' as money), CAST('$2,345.56556' as money)

Cast( cast('2,344' as money) as float) 将完美运行或 cast( cast('2,344' as money) as decimal(7,2)) 也可以。

即使 cast(CAST('$2,345.56556' as money) as int ) 也可以完美地将其四舍五入到最接近的整数。

【讨论】:

    【解决方案3】:

    SQL 非数字存在许多问题。例如:

    select isnumeric('1e5')
    

    这将返回 1,但在许多语言中,如果您尝试将其转换为数字,它将失败。更好的方法是使用您需要检查的参数创建您自己的用户定义函数:

    http://www.tek-tips.com/faqs.cfm?fid=6423

    【讨论】:

    • 更好的是:首先不要将数字字段存储在字符串列中。
    【解决方案4】:

    当输入表达式的计算结果为有效整数、浮点数、货币或小数类型时,ISNUMERIC 返回 1;

    所以问题是它是一个有效的数字,但不是一个有效的 int。

    【讨论】:

    • 我看到了,但是当尝试将值转换为浮点数时,我遇到了同样的问题。
    【解决方案5】:

    凯尔,

    我认为这可以解决问题。问题在于 ELSE 子句将您的结果初始化为 INTEGER。通过对 FLOAT 进行显式类型转换并添加 Quassnoi 的建议,它似乎可以工作。

    DECLARE @MyTable TABLE (Column1 VARCHAR(50))
    INSERT INTO @MyTable VALUES('11.6')
    INSERT INTO @MyTable VALUES('-1')
    INSERT INTO @MyTable VALUES('1,000')
    INSERT INTO @MyTable VALUES('10"    ')
    INSERT INTO @MyTable VALUES('Non-Numeric String')
    
    SELECT CASE WHEN ISNUMERIC(REPLACE(Column1,'"','')) = 1 THEN REPLACE(REPLACE(Column1,'"',''), ',', '.') ELSE CAST(0 AS FLOAT) END
    FROM @MyTable
    

    问候,
    利文

    【讨论】:

      【解决方案6】:

      IsNumeric(' ') 也返回 1,但随后 CAST as int 爆炸了。上面的 Brendan 说编写你自己的函数。他是对的。

      【讨论】:

      • 在我的 SQL 2008 机器上,IsNumeric(' ') 返回 0
      【解决方案7】:

      此解决方案并非在所有情况下都有效(特别是带有货币和/或千位分隔符的数字)。将指数表示连接到由字符串表示的数字的末尾...ISNUMERIC() 从那里可以正常工作。以下示例:

      -- CURRENT ISNUMERIC RESULTS
      SELECT ISNUMERIC('11.6'); --1
      SELECT ISNUMERIC ('-1'); --1
      SELECT ISNUMERIC('1,000'); --1
      SELECT ISNUMERIC('10"'); --0
      SELECT ISNUMERIC('$10'); --1
      
      -- NEW ISNUMERIC RESULTS
      SELECT ISNUMERIC('11.6'+'e+00'); --1
      SELECT ISNUMERIC ('-1'+'e+00'); --1
      SELECT ISNUMERIC('1,000'+'e+00'); --0
      SELECT ISNUMERIC('10"'+'e+00'); --0
      SELECT ISNUMERIC('$10'+'e+00'); --0
      

      这至少标准化了使用 REPLACE() 函数的格式。

      【讨论】:

        【解决方案8】:

        我刚遇到这个问题。

        如果您不介意十进制长度的限制,可以尝试此解决方案。

        CONVERT(numeric, CONVERT(money, '.')) 
        

        注意:

        1. SQL Server 2008 或更高版本支持
        2. 货币范围是:-922,337,203,685,477.5808 到 922,337,203,685,477.5807 - 四位小数

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-04-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多