这里有两个主要问题。
首先是找到一个函数,该函数将全面确定您的 NVARCHAR 列中的值是否真的代表一个数字。第二个是确保 CASE 语句的 THEN 元素在不需要时不会计算。
正如您所注意到的,内置的 TRANSLATE 功能可以做得不错,但它并非万无一失。据我所知,没有内置函数可以可靠地执行此检查。
但是,有两个包含的 UDF 可以很好地完成这项任务。这两个功能都必须由您的管理员明确启用。
- isnumber ,包含在 INZA 函数中
- regexp_like ,包含在 SQL 扩展工具包中
以下是同时使用这两种方法的示例,显示了对 SMALLINT 的强制转换。在每一个中,我都将测试 CASE 放在一个子选择中,以确保最终的 CAST 不会与原始值绝缘。您可能认为只能在两个嵌套的 CASE 中对此进行编码,但对于 UDF,您不能总是依赖这种行为。
isnumber 示例:
SELECT ORIG_COL,
CASE
WHEN COL1 BETWEEN -32678 AND 32767
THEN COL1::SMALLINT
ELSE NULL
END THE_NUMBER
FROM (
SELECT
COL1 ORIG_COL,
CASE
WHEN isnumber(COL1)
THEN COL1
ELSE NULL
END COL1
FROM test_cast
)
t1;
ORIG_COL | THE_NUMBER
----------+------------
NAN |
1 | 1
-+9,9.09 |
99999 |
(4 rows)
regexp_like 示例,使用@Niederee 在他对this question 的回答中提供的模式。
SELECT ORIG_COL,
CASE
WHEN COL1 BETWEEN -32678 AND 32767
THEN COL1::SMALLINT
ELSE NULL
END THE_NUMBER
FROM (
SELECT COL1 ORIG_COL,
CASE
WHEN REGEXP_LIKE(COL1, '^[+-]?[0-9]*[.]?[0-9]*$')
THEN COL1
ELSE NULL
END COL1
FROM test_cast
)
t1;
ORIG_COL | THE_NUMBER
----------+------------
99999 |
NAN |
1 | 1
-+9,9.09 |
(4 rows)
请记住,您需要您的管理员才能为您提供这些功能。
isnumber函数来自INZA安装,如果INZA安装到位,可以这样加载:
[nz@netezza ~]$ cd /nz/extensions/nz/nzlua/examples/
[nz@netezza examples]$ ../bin/nzl -d testdb isnumber.nzl
Compiling: isnumber.nzl
####################################################################
UdxName = isnumber
UdxType = UDF
Arguments = VARCHAR(ANY)
Result = BOOL
Dependencies = INZA.INZA.LIBNZLUA_3_2_0
NZUDXCOMPILE OPTIONS: (--replbyval --nullcall --unfenced --mem 2m)
CREATE FUNCTION
[nz@netezza examples]$
SQL 扩展工具包的安装过程有很好的文档记录,其中包含 regexp_like 函数。