我试图在一个非常大的 Oracle 表中找到一些有问题的记录。该列应包含所有数字数据,即使它是 varchar2 列。我需要找到不包含数字数据的记录(当我尝试在此列上调用 to_number(col_name) 函数时会引发错误)。
11 回答
我在想你可以使用 regexp_like 条件并使用正则表达式来查找任何非数字。我希望这可能会有所帮助?!
SELECT * FROM table_with_column_to_search WHERE REGEXP_LIKE(varchar_col_with_non_numerics, '[^0-9]+');
获取指标:
DECODE( TRANSLATE(your_number,' 0123456789',' ')
例如
SQL> select DECODE( TRANSLATE('12345zzz_not_numberee',' 0123456789',' '), NULL, 'number','contains char')
2 from dual
3 /
"contains char"
和
SQL> select DECODE( TRANSLATE('12345',' 0123456789',' '), NULL, 'number','contains char')
2 from dual
3 /
"number"
和
SQL> select DECODE( TRANSLATE('123405',' 0123456789',' '), NULL, 'number','contains char')
2 from dual
3 /
"number"
Oracle 11g 具有正则表达式,因此您可以使用它来获取实际数字:
SQL> SELECT colA
2 FROM t1
3 WHERE REGEXP_LIKE(colA, '[[:digit:]]');
COL1
----------
47845
48543
12
...
如果有像“23g”这样的非数字值,它将被忽略。
与 SGB 的答案相反,我更喜欢使用正则表达式来定义我的数据的实际格式并否定它。这允许我定义像 $DDD,DDD,DDD.DD 这样的值 在 OPs 简单场景中,它看起来像
SELECT *
FROM table_with_column_to_search
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^[0-9]+$');
它找到所有非正整数。如果您也接受负整数,这是一个简单的更改,只需添加一个可选的前导减号。
SELECT *
FROM table_with_column_to_search
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+$');
接受浮点数...
SELECT *
FROM table_with_column_to_search
WHERE NOT REGEXP_LIKE(varchar_col_with_non_numerics, '^-?[0-9]+(\.[0-9]+)?$');
任何格式都一样。基本上,您通常已经拥有验证输入数据的格式,因此当您希望找到与该格式不匹配的数据时……否定该格式比提出另一种格式更简单;如果您想要的不仅仅是正整数,那么在 SGB 的方法中会有点棘手。
用这个
SELECT *
FROM TableToSearch
WHERE NOT REGEXP_LIKE(ColumnToSearch, '^-?[0-9]+(\.[0-9]+)?$');
在做了一些测试之后,我想出了这个解决方案,如果它有帮助,请告诉我。
在您的查询中添加以下 2 个条件,它将找到不包含数字数据的记录
and REGEXP_LIKE(<column_name>, '\D') -- this selects non numeric data
and not REGEXP_LIKE(column_name,'^[-]{1}\d{1}') -- this filters out negative(-) values
来自http://www.dba-oracle.com/t_isnumeric.htm
LENGTH(TRIM(TRANSLATE(, ' +-.0123456789', ' '))) is null
如果在 TRIM 之后的字符串中还有任何内容,则它必须是非数字字符。
从 Oracle 12.2 开始,函数to_number有一个选项ON CONVERSION ERROR
子句,可以捕获异常并提供默认值。
这可用于数字值的测试。NULL
转换失败时的简单设置,并且 filer都不是 NULL值。
例子
with num as (
select '123' vc_col from dual union all
select '1,23' from dual union all
select 'RV12P2000' from dual union all
select null from dual)
select
vc_col
from num
where /* filter numbers */
vc_col is not null and
to_number(vc_col DEFAULT NULL ON CONVERSION ERROR) is not null
;
VC_COL
---------
123
1,23
在进行了一些测试之后,在前面答案中的建议的基础上,似乎有两个可用的解决方案。
方法 1 最快,但在匹配更复杂的模式方面功能较弱。
方法 2 更灵活,但速度较慢。
方法 1 - 最快
我在一个有 100 万行的表上测试了这个方法。
它似乎比正则表达式解决方案快 3.8 倍。
0 替换解决了 0 映射到空格的问题,并且似乎不会减慢查询速度。
SELECT *
FROM <table>
WHERE TRANSLATE(replace(<char_column>,'0',''),'0123456789',' ') IS NOT NULL;
方法 2 - 速度较慢,但更灵活
我比较了将否定置于正则表达式语句内部或外部的速度。两者都比翻译解决方案慢。因此,@ciuly 的方法在使用正则表达式时似乎最明智。
SELECT *
FROM <table>
WHERE NOT REGEXP_LIKE(<char_column>, '^[0-9]+$');
我发现这很有用:
select translate('your string','_0123456789','_') from dual
如果结果为 NULL,则为数字(忽略浮点数。)
但是,我有点困惑为什么需要下划线。没有它,以下内容也返回 null:
select translate('s123','0123456789', '') from dual
还有一个我最喜欢的技巧 - 如果字符串包含诸如“*”或“#”之类的东西,那就不完美了:
SELECT 'is a number' FROM dual WHERE UPPER('123') = LOWER('123')
SELECT
D.UNIT_CODE,
D.CUATM,
D.CAPITOL,
D.RIND,
D.COL1 AS COL1
FROM
VW_DATA_ALL_GC D
WHERE
(D.PERIOADA IN (:pPERIOADA)) AND
(D.FORM = 62)
AND D.COL1 IS NOT NULL
-- AND REGEXP_LIKE (D.COL1, '\[\[:alpha:\]\]')
-- AND REGEXP_LIKE(D.COL1, '\[\[:digit:\]\]')
--AND REGEXP_LIKE(TO_CHAR(D.COL1), '\[^0-9\]+')
GROUP BY
D.UNIT_CODE,
D.CUATM,
D.CAPITOL,
D.RIND ,
D.COL1
ORDER BY
D.COL1
您可以使用这一项检查:
create or replace function to_n(c varchar2) return number is
begin return to_number(c);
exception when others then return -123456;
end;
select id, n from t where to_n(n) = -123456;