TSQL - 替换 isnumeric = 0

Posted

技术标签:

【中文标题】TSQL - 替换 isnumeric = 0【英文标题】:TSQL - replace isnumeric = 0 【发布时间】:2018-03-16 13:43:19 【问题描述】:

我有一个 select 语句,并且在该 select 语句中我有几列用于执行基本计算(例如 [Col1] * 3.14)。但是,有时我会遇到非数字值,当这种情况发生时,整个存储过程会因为一行而失败。

我曾考虑过使用WHERE ISNUMERIC(Col1) <> 0,但我会排除其他列中的信息。

TSQL 中是否有办法以某种方式将所有字符串替换为 NULL 或 0??

【问题讨论】:

使用 TRY_CAST() 而不是 ISNUMERIC() 来避免一些可能的麻烦。 ISNUMERIC 回答了 nobody 想要回答的问题 - “这个字符串是否可以转换为至少一种数字数据类型,我不在乎哪些具体来说?”。很好。您想要一个 decimal 并且字符串只能转换为 money 类型这一事实确实为您带来了进步...... 【参考方案1】:

类似...

SELECT blah1, blah2, blah3
   CASE WHEN ISNUMERIC(Col1) = 1 THEN [Col1] * 3.14 ELSE NULL END as whatever
FROM your_table

也可以做个案例..

如果这是列中的预期值,非数字值应转换为数字或 NULL,并且 如果需要数字,则该列首先应该是数字数据类型,而不是字符数据类型,这允许出现这些类型的错误。

【讨论】:

insert into your_table (blah1,blah2,blah3,Col1) values (1,2,3,'$4.0') 试试这个,你仍然会得到一个错误——ISNUMERIC 的一个例子。【参考方案2】:

我更喜欢 Try_Cast:

SELECT
    someValue
    ,TRY_CAST(someValue as int) * 3.14     AS TRY_CAST_to_int
    ,TRY_CAST(someValue as decimal) * 3.14 AS TRY_CAST_to_decimal
    ,IIF(ISNUMERIC(someValue) = 1, someValue, null) * 3.14 as IIF_IS_NUMERIC
FROM (values 
    ( 'asdf'), 
    ( '2' ),
    ( '1.55')
) s(someValue)

【讨论】:

【参考方案3】:

ISNUMERIC 是一种糟糕的方法,因为有太多东西标识为NUMERIC,它们无法乘以非MONEY 数据类型。

https://www.brentozar.com/archive/2018/02/fifteen-things-hate-isnumeric/

这很失败,因为'-'是一个数字......

DECLARE @example TABLE (numerics VARCHAR(10));

INSERT INTO @example VALUES ('-')

SELECT CASE WHEN ISNUMERIC(numerics) = 1 THEN numerics  * 3.14 ELSE NULL END  
FROM @example;

改用TRY_CAST(尽管修改您的 DECIMAL 精度以满足您的需要):

DECLARE @example TABLE (numerics VARCHAR(10));

INSERT INTO @example VALUES ('-')

SELECT TRY_CAST(numerics AS decimal(10,2)) * 3.14  FROM @example;

【讨论】:

"有太多东西被识别为 NUMERIC 而不是。" - 不对。任何导致ISNUMERIC 返回 1 的内容都可以转换为至少一种数字数据类型。问题是,我们不关心这种模糊的可能性——我们关心它是否可以转换为 特定 数字数据类型,这不是ISNUMERIC 回答的问题。例如。 select CONVERT(money,'-') 是一个完全有效的转换。但您不在乎,因为您不打算将 '-' 转换为 money 数据类型。【参考方案4】:

trycast 将测试特定类型

declare @T table (num varchar(20));
insert into @T values ('12'), ('3.14'), ('5.6E12'), ('$120'), ('-'), (''), ('cc'), ('aa'), ('bb'), ('1/5'); 
select t.num, ISNUMERIC(t.num) as isnumeric
     , isnull(TRY_CONVERT(smallmoney, t.num), 0) as smallmoney 
     , TRY_CONVERT(float, t.num) as float
     , TRY_CONVERT(decimal(18,4), t.num) as decimal 
     , isnull(TRY_CONVERT(smallmoney, t.num), TRY_CONVERT(float, t.num)) as mix
from @T t

num                  isnumeric   smallmoney            float                  decimal
-------------------- ----------- --------------------- ---------------------- ---------------------------------------
12                   1           12.00                 12                     12.0000
3.14                 1           3.14                  3.14                   3.1400
5.6E12               1           0.00                  5600000000000          NULL
$120                 1           120.00                NULL                   NULL
-                    1           0.00                  NULL                   NULL
                     0           0.00                  0                      NULL
cc                   0           0.00                  NULL                   NULL
aa                   0           0.00                  NULL                   NULL
bb                   0           0.00                  NULL                   NULL
1/5                  0           0.00                  NULL                   NULL

有趣的是最后还是失败了

【讨论】:

以上是关于TSQL - 替换 isnumeric = 0的主要内容,如果未能解决你的问题,请参考以下文章

sql server2008 字符串的替换

TSQL使用变量重新连接字符串文本

TSQL:是不是有更快或更好的加密值的方法?

将 PL/SQL 定义转换为 TSQL

isnumeric()方法

Python isnumeric()方法