检查Oracle中是否有“数字”function

我试图检查一个oracle(10g)查询中的列的值是否是一个数字,以便比较它。 就像是:

select case when ( is_number(myTable.id) and (myTable.id >0) ) then 'Is a number greater than 0' else 'it is not a number' end as valuetype from table myTable 

任何想法如何检查?

假设myTable中的ID列没有被声明为一个NUMBER(这似乎是一个奇怪的select,并可能有问题),您可以编写一个函数,试图将(大概VARCHAR2)ID转换为一个数字,捕获exception,并返回“Y”或“N”。 就像是

 CREATE OR REPLACE FUNCTION is_number( p_str IN VARCHAR2 ) RETURN VARCHAR2 DETERMINISTIC PARALLEL_ENABLE IS l_num NUMBER; BEGIN l_num := to_number( p_str ); RETURN 'Y'; EXCEPTION WHEN value_error THEN RETURN 'N'; END is_number; 

然后,您可以将该调用embedded到查询中,即

 SELECT (CASE WHEN is_number( myTable.id ) = 'Y' AND myTable.id > 0 THEN 'Number > 0' ELSE 'Something else' END) some_alias FROM myTable 

请注意,尽pipePL / SQL具有布尔型数据types,但SQL不具有。 所以虽然你可以声明一个返回布尔值的函数,但你不能在SQL查询中使用这样的函数。

另一个想法, 这里提到的是使用正则expression式来检查:

 SELECT foo FROM bar WHERE REGEXP_LIKE (foo,'^[[:digit:]]+$'); 

好的部分是你不需要单独的PL / SQL函数。 可能有问题的部分是正则expression式可能不是大量行的最有效的方法。

Saish的回答使用REGEXP_LIKE是正确的想法,但不支持浮动数字。 这个会…

返回数字的值

 SELECT foo FROM bar WHERE REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$'); 

返回值不是数字

 SELECT foo FROM bar WHERE NOT REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$'); 

你可以自己testing一下你的正则expression式,直到你的内容在http://regexpal.com/ (但是确保你select这个checkbox匹配的换行符 )。

您可以在ORACLE(10g)中使用正则expression式函数“regexp_like”,如下所示:

 select case when regexp_like(myTable.id, '[[:digit:]]') then case when myTable.id > 0 then 'Is a number greater than 0' else 'Is a number less than or equal to 0' end else 'it is not a number' end as valuetype from table myTable 

这是在Oracle中查找不包含数字数据的行的潜在副本。 另请参阅: 如何确定SQL中的string是否为数字? 。

这是一个基于迈克尔·杜兰特的解决scheme,用于整数。

 SELECT foo FROM bar WHERE DECODE(TRIM(TRANSLATE(your_number,'0123456789',' ')), NULL, 'number','contains char') = 'number' 

Adrian Carneiro发布了一个适用于小数和其他的解决scheme。 但是,Justin Cave指出,这会错误地将string分类为“123.45.23.234”或“131 + 234”。

 SELECT foo FROM bar WHERE DECODE(TRIM(TRANSLATE(your_number,'+-.0123456789',' ')), NULL, 'number','contains char') = 'number' 

如果你需要一个没有PL / SQL或REGEXP_LIKE的解决scheme,这可能会有所帮助。

我反对使用when others所以我会使用(返回一个“布尔整数”由于SQL不支持布尔)

 create or replace function is_number(param in varchar2) return integer is ret number; begin ret := to_number(param); return 1; --true exception when invalid_number then return 0; end; 

在SQL调用中,你会使用类似的东西

 select case when ( is_number(myTable.id)=1 and (myTable.id >'0') ) then 'Is a number greater than 0' else 'it is not a number or is not greater than 0' end as valuetype from table myTable 

该列是如何定义的? 如果它的一个varchar字段,那么它不是一个数字(或存储为一个)。 Oracle可能可以为你做转换(例如,select * from someTable where charField = 0),但是它只会返回转换为真且可能的行。 这也远非理想状况performance明智。

所以,如果你想做数字比较,并把这个列作为一个数字,也许它应该被定义为一个数字?

这就是说,你可能会这样做:

 create or replace function myToNumber(i_val in varchar2) return number is v_num number; begin begin select to_number(i_val) into v_num from dual; exception when invalid_number then return null; end; return v_num; end; 

您也可以包含常规to_number具有的其他参数。 如此使用:

 select * from someTable where myToNumber(someCharField) > 0; 

它不会返回任何Oracle认为无效的行的行。

干杯。

 CREATE OR REPLACE FUNCTION is_number(N IN VARCHAR2) RETURN NUMBER IS BEGIN RETURN CASE regexp_like(N,'^[\+\-]?[0-9]*\.?[0-9]+$') WHEN TRUE THEN 1 ELSE 0 END; END is_number; 

请注意,它不会将45e4视为一个数字,但您可以随时更改正则expression式来完成相反的操作。

@JustinCave – “when value_error”replace“when others”是对上述方法的一个很好的改进。 这个稍微额外的调整,虽然在概念上是相同的,但不需要定义和随后的内存分配给你的l_numvariables:

 function validNumber(vSomeValue IN varchar2) return varchar2 DETERMINISTIC PARALLEL_ENABLE is begin return case when abs(vSomeValue) >= 0 then 'T' end; exception when value_error then return 'F'; end; 

对于任何喜欢使用“高风险”REGEXP方法模拟Oracle数字格式逻辑的人来说,请不要忘记考虑NLS_NUMERIC_CHARACTERS和NLS_TERRITORY。

那么,你可以创buildis_number函数来调用你的代码。

 create or replace function is_number(param varchar2) return boolean as ret number; begin ret := to_number(param); return true; exception when others then return false; end; 

编辑:请按照贾斯汀的答案。 忘记了一个纯粹的SQL调用的小细节….

这是我的查询find所有那些不是数字:

 Select myVarcharField From myTable where not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\.\d+)?$', '') and not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\,\d+)?$', ''); 

在我的领域,我已经。 而且十进制数字很可悲,所以必须考虑到这一点,否则你只需要其中一个限制。

移动号码长度为10位,从9,8,7开始使用正则expression式

 create or replace FUNCTION VALIDATE_MOBILE_NUMBER ( "MOBILE_NUMBER" IN varchar2 ) RETURN varchar2 IS v_result varchar2(10); BEGIN CASE WHEN length(MOBILE_NUMBER) = 10 AND MOBILE_NUMBER IS NOT NULL AND REGEXP_LIKE(MOBILE_NUMBER, '^[0-9]+$') AND MOBILE_NUMBER Like '9%' OR MOBILE_NUMBER Like '8%' OR MOBILE_NUMBER Like '7%' then v_result := 'valid'; RETURN v_result; else v_result := 'invalid'; RETURN v_result; end case; END; 

我相信下面的解决scheme(基于上面的regexp_like方法)是最优的:

 function isInteger(vYourValue IN varchar2) return varchar2 is begin return case REGEXP_INSTR(vYourValue,'^[[:digit:]]+$') when 0 then 'F' else 'T' end; end; 

我为什么这么说?

  1. 被testing的数字子集可以根据需要通过适当地改变正则expression式来修改。

  2. 它可以在SQL中使用,即从mytable中selectisInteger(myCol); 因为它返回'F'的'T'而不是布尔值。

  3. 它可以在pl / sql中原生使用。 如果isInteger(vMyValue)='T'那么….

  4. 它满足WNDS,WNPS纯度断言。

  5. 在我看来,它并不依赖于“其他人”在确定结果方面的广泛范围。

请注意,正则expression式或函数方法比纯sql条件慢几倍 。

因此,一些适用性有限的启发式解决方法使大型扫描成为可能。

如果您确实知道非数字值将包含某些字母,则有一种解决scheme :

 select case when upper(dummy)=lower(dummy) then '~numeric' else '~alpabetic' end from dual 

如果你知道一些字母总是会出现在非数字的情况下:

 select case when instr(dummy, 'X')>0 then '~alpabetic' else '~numeric' end from dual 

当数字情况总是包含零时:

 select case when instr(dummy, '0')=0 then '~alpabetic' else '~numeric' end from dual 

如果条件为null,那么它是数字

 IF(rtrim(P_COD_LEGACY, '0123456789') IS NULL) THEN return 1; ELSE return 0; END IF;