检查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;
我为什么这么说?
-
被testing的数字子集可以根据需要通过适当地改变正则expression式来修改。
-
它可以在SQL中使用,即从mytable中selectisInteger(myCol); 因为它返回'F'的'T'而不是布尔值。
-
它可以在pl / sql中原生使用。 如果isInteger(vMyValue)='T'那么….
-
它满足WNDS,WNPS纯度断言。
-
在我看来,它并不依赖于“其他人”在确定结果方面的广泛范围。
请注意,正则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;