【问题标题】:error converting varchar to float将 varchar 转换为 float 时出错
【发布时间】:2011-11-10 19:13:49
【问题描述】:

将 varchar 转换为 float 时出错。

有一个表(不是我制作的),列有 result,有 varchar 数据。我想转换为浮点数以获取所有大于 180.0 的值。

SELECT result FROM table WHERE result > 180.0

产生错误。不过有趣的是:

WITH temp AS (
  CASE
    WHEN ISNUMERIC(result)=1 THEN CAST(result as FLOAT)
    ELSE CAST(-1.0 AS FLOAT)
  END AS result
)

这运行良好。当我与它配对时:

SELECT temp.result FROM temp WHERE temp.result > 180.0

我再次收到错误消息。想法?

更新:请求完整代码...

WITH temp AS (
  SELECT
  CASE
    WHEN ISNUMERIC(result)=1 THEN CAST(result as FLOAT)
    ELSE CAST(-1.0 AS FLOAT)
  END AS result
  FROM table)

SELECT temp.result FROM temp WHERE temp.result > 180.0

使用 SQL-SERVER 2008 RC2。

【问题讨论】:

  • 你能给出你使用的确切语法吗?您的WITH .. AS (CASE ... ) 不完整且不正确。
  • 我试图重现错误但无法...我将以下内容放在您发布并从@t 中选择的代码之前并返回 199。声明@t 表(结果 varchar(500) ) 插入@t(结果)值('199.00')插入@t(结果)值('test');
  • @Jeremy:您需要一个通过ISNUMERIC 测试但无法转换的测试值,例如'1,0'

标签: sql-server tsql


【解决方案1】:

这意味着您在表格中至少有一行无法转换为float。执行CASE 是安全的,但是在编写T-SQL 时结合CTE 和添加WHERE 子句会落入程序员的常见谬误:声明顺序意味着执行顺序。程序员已经习惯了类 C 语言的命令式过程风格,并且无法理解 SQL 的基于声明集的性质。我之前写过关于这个问题的文章,并给出了谬误导致错误的例子:

一旦您发布了完整的代码,我们就可以看到您究竟在哪里犯了错误,并假设了特定的执行顺序。

更新后

好的,所以我必须管理,在你的情况下,代码在执行顺序上是正确的,result 列不能在没有首先评估CASE 的情况下被投影。如果 CASE 在 WHERE 子句中,情况会有所不同。

您的问题不同:ISNUMERIC。这个功能对NUMERIC的含义有非常大的理解,之前也被很多开发者咬过。也就是说,它接受 CAST 和 CONVERT 将拒绝的值。像那些包含逗号的:

declare @n varchar(8000) = '1,000';
select isnumeric(@n);
select cast(@n as float);
select case when isnumeric(@n)=1 then cast(@n as float) else null end;

因此,您的值通过了ISNUMERIC 测试但未能转换。只是提醒一下,你越深入研究这种方法,你就会发现越多的封闭的门。在服务器端进行所需的演员阵容只是没有安全的方法。理想情况下,修复数据模型(如果字段存储浮点数,则将其设为浮点数)。除此之外,对数据进行分类并删除所有不正确的浮点值,并修复前端/应用程序不再引入新值,然后添加一个约束,如果出现新的错误值将触发错误。你将无法在查询中解决这个问题,那条路上到处都是尸体。

在 SQL Server 的下一个版本中,您将拥有一个新函数 TRY_CONVERT,它将解决您的问题。

【讨论】:

  • 不幸的是,我无法更改数据库的设计 :( 是否有一个常见的习惯用法让 SQL Server 吐出它无法 CAST / CONVERT 的行?
  • 不幸的是,这种特殊情况下 IsNumeric issatified 但像 cast(result) 这样的记录由于逗号而失败是很常见的。您可以使用 REPLACE(result,',','') 之类的语句删除逗号。如果可能的话,最好在上游修复它。
【解决方案2】:

看看这个:

http://classicasp.aspfaq.com/general/what-is-wrong-with-isnumeric.html

基本上,ISNUMERIC 函数存在一些已知问题/奇怪之处。那篇文章的作者建议创建一个新函数并使用它而不是 ISNUMERIC。我使用您建议的 1,0 值对其进行了测试,它似乎有效。


CREATE FUNCTION dbo.isReallyNumeric  
(  
    @num VARCHAR(64)  
)  
RETURNS BIT  
BEGIN  
    IF LEFT(@num, 1) = '-'  
        SET @num = SUBSTRING(@num, 2, LEN(@num))  

    DECLARE @pos TINYINT  

    SET @pos = 1 + LEN(@num) - CHARINDEX('.', REVERSE(@num))  

    RETURN CASE  
    WHEN PATINDEX('%[^0-9.-]%', @num) = 0  
        AND @num NOT IN ('.', '-', '+', '^') 
        AND LEN(@num)>0  
        AND @num NOT LIKE '%-%' 
        AND  
        (  
            ((@pos = LEN(@num)+1)  
            OR @pos = CHARINDEX('.', @num))  
        )  
    THEN  
        1  
    ELSE  
    0  
    END  
END  
GO 

【讨论】:

  • 效果很好,它发现一个负数正在停止浮动转换
【解决方案3】:

简单的显式转换,但需要一点独创性的 REPLACE

SELECT result FROM table WHERE CONVERT(float,REPLACE(result,',','.')) > 180.0

【讨论】:

    猜你喜欢
    • 2013-06-11
    • 2020-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-08
    • 2019-01-22
    相关资源
    最近更新 更多