3

我正在尝试将我的数据库字段VARCHAR(4)FLOAT. 这些字段中的某些值可能不是数字,因为这些字段之前没有任何验证。我的主要目标是以浮点格式转换任何integerdecimal值并保存在新的数据库字段中。对于这个过程,我使用INSERT SELECT STATEMENT从旧表到新表。到目前为止,我有这行代码用于我的转换:

CASE WHEN LEN(LTRIM(RTRIM(hs_td2))) <> 0 AND ISNUMERIC(hs_td2) = 1 THEN CAST(LTRIM(RTRIM(hs_td2)) AS float) ELSE NULL END AS hs_td2

第一步,我修剪该值,然后检查它是否为数字,然后转换为浮点数,否则设置为 NULL。使用上面的代码,我在 Microsoft Studio 中收到此错误消息:

Msg 8114, Level 16, State 5, Line 13
Error converting data type varchar to float.

第 13 行是我SELECT声明的开始。然后我也尝试了这种转换:

CASE WHEN LEN(LTRIM(RTRIM(hs_td2))) <> 0 AND ISNUMERIC(hs_td2) = 1 THEN CONVERT(FLOAT, LTRIM(RTRIM(hs_td2))) ELSE NULL END AS hs_td2

我得到了同样的错误信息。我的字段中的值可能是这样的:

10 或 5 或 -10 或 0.9 或 11.6 或 -11.89 等等......

我想知道是否isNumeric()是我应该使用的最佳功能以及为什么我的代码会产生上面列出的错误消息?

如果有人可以提供帮助,请告诉我。谢谢!

4

3 回答 3

2

不,ISNUMERIC不是最好的功能。

本质上,这个问题之前已经被问过,虽然不是在这个措辞中:

适用于 SQL Server 2008 R2 的 Try_Convert

最受欢迎的答案建议转换为 XML 以使用特定于 XML 的转换功能:

DECLARE @T TABLE (v varchar(4));

INSERT INTO @T (v) VALUES
('1g23'),
('-1.8'),
('11.6'),
('akjh'),
('.'),
('-'),
('$'),
('12,5');


select
    cast('' as xml).value('sql:column("V") cast as xs:float ?', 'float') as new_v
from @T

我将在下面留下我的第一个答案版本。

您很可能会收到转换错误,因为服务器尝试为CAST(LTRIM(RTRIM(hs_td2)) AS float)表的每一行运行,而不仅仅是那些数字。

当您尝试使用过滤器过滤掉非数字行时,通常会发生这种情况WHERE ISNUMERIC(...) = 1。从技术上讲,它也可能发生在CASE表达中。

这就是他们TRY_CONVERT在 2012 年添加的原因。

我会尝试编写自己的用户定义函数,该函数使用TRY-CATCH并尝试转换给定值。是的,它会很慢。


话虽如此,下面的示例CASE运行良好:

DECLARE @T TABLE (v varchar(4));

INSERT INTO @T (v) VALUES
('123'),
('-1.8'),
('11.6'),
('akjh'),
('123');

SELECT
    CASE WHEN ISNUMERIC(v) = 1 THEN CAST(v AS float) ELSE NULL END AS new_v
FROM @T;

结果

+-------+
| new_v |
+-------+
| 123   |
| -1.8  |
| 11.6  |
| NULL  |
| 123   |
+-------+

但是,如果我输入一个.-$值,就像这样:

INSERT INTO @T (v) VALUES
('123'),
('-1.8'),
('11.6'),
('akjh'),
('$');

查询失败:

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

可能还有其他特殊字符及其组合ISNUMERIC不会抱怨。这就是为什么我最初说总体而言,ISNUMERIC不是最好的功能。

如果是一次性转换,您可以尝试构建一个LIKE表达式来捕获数据中存在的所有特殊情况,但如果您需要可靠的通用解决方案,请升级到 2012+ 并使用TRY_CONVERT或编写您的 T-SQL UDF ,或您的 CLR UDF。

于 2017-09-18T13:19:08.057 回答
1

Sqlxml 有足够的力量来制造魔法。当然,性能是问题。但还是比百万条件好

DECLARE @T TABLE (v varchar(4));

INSERT INTO @T (v) VALUES
('123'),('-1.8'),('11.6'),('akjh'),('$'),('-.'),('-.1'),(NULL);

declare @Xml xml = (SELECT v  FROM @T T for xml auto,elements);

select T.v.value('v[1]','varchar(4)') v, T.v.value('max(v[1])','float') converted_v 
from @xml.nodes('/T') T(v);
于 2017-09-18T14:43:19.363 回答
0

这取决于您的 varchar 列中的值

ISNUMBER() 用于'.'等值 '-'将返回 1,但是,当你 CAST 到 FLOAT 时它会失败

对于诸如'3D2 ' 、'1e2 ' 之类的值的 ISNUMBER() 将返回 1,并且可以 CAST 为 FLOAT,但是,您可能不希望将其视为数字。

您可以尝试以下方法进行转换

CASE WHEN 
  not LTRIM(RTRIM(hs_td2))like '%[^0-9.,-]%'    -- Value only contains 0-9 . -
  and LTRIM(RTRIM(hs_td2)) not like '.'          -- can not be only .
  and LTRIM(RTRIM(hs_td2)) not like '-'          -- can not be only -
  and isnumeric(LTRIM(RTRIM(hs_td2))) = 1  
THEN CAST(LTRIM(RTRIM(hs_td2)) AS float) 
ELSE NULL 
END
于 2017-09-18T13:41:01.683 回答