我正在尝试检查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
关于如何检查的任何想法?
答案 0 :(得分:61)
提到here的另一个想法是使用正则表达式来检查:
SELECT foo
FROM bar
WHERE REGEXP_LIKE (foo,'^[[:digit:]]+$');
好的部分是你不需要单独的PL / SQL函数。可能存在问题的部分是正则表达式可能不是大量行的最有效方法。
答案 1 :(得分:32)
假设myTable
中的ID列未声明为NUMBER(这似乎是一个奇怪的选择并且可能有问题),您可以编写一个尝试将(可能是VARCHAR2)ID转换为一个数字,捕获异常,并返回'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;
然后,您可以在查询中嵌入该调用,即
SELECT (CASE WHEN is_number( myTable.id ) = 'Y' AND myTable.id > 0
THEN 'Number > 0'
ELSE 'Something else'
END) some_alias
FROM myTable
请注意,尽管PL / SQL具有布尔数据类型,但SQL却没有。因此,虽然您可以声明一个返回布尔值的函数,但您不能在SQL查询中使用这样的函数。
答案 2 :(得分:15)
Saish使用REGEXP_LIKE
的答案是正确的想法,但不支持浮动数字。这个会...
返回数字
的值SELECT foo
FROM bar
WHERE REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');
返回值不是数字
SELECT foo
FROM bar
WHERE NOT REGEXP_LIKE (foo,'^-?\d+(\.\d+)?$');
您可以自己测试正则表达式,直到您的心满意为http://regexpal.com/(但请务必选中在换行符时匹配)。
答案 3 :(得分:5)
这是Finding rows that don't contain numeric data in Oracle的潜在副本。另请参阅:How can I determine if a string is numeric in SQL?。
这是一个基于Michael Durrant's的解决方案,适用于整数。
SELECT foo
FROM bar
WHERE DECODE(TRIM(TRANSLATE(your_number,'0123456789',' ')), NULL, 'number','contains char') = 'number'
Adrian Carneiro发布了一个适用于小数和其他的解决方案。但是,正如Justin Cave指出的那样,这会错误地将字符串分类为'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的解决方案,这可能会有所帮助。
答案 4 :(得分:5)
您可以在ORACLE(10g)中使用正则表达式函数'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
答案 5 :(得分:2)
我反对使用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
答案 6 :(得分:1)
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视为数字,但您可以随时更改正则表达式以完成相反的操作。
答案 7 :(得分:1)
如何定义列?如果是一个varchar字段,那么它不是一个数字(或存储为一个)。 Oracle可能能够为您进行转换(例如,从someTable中选择*,其中charField = 0),但它只会返回转换成立且可能的行。这也远非理想情况下的表现。
那么,如果您想进行数字比较并将此列视为数字,或许它应该被定义为数字?
那就是说,这就是你可能会做的事情:
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认为无效数字的任何行。
干杯。
答案 8 :(得分:1)
@JustinCave - "当value_error"替换"当其他人"对您的方法进行了很好的改进。这个轻微的额外调整虽然在概念上是相同的,但不需要为l_num变量定义和后续内存分配:
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;
对于任何喜欢使用"风险较高的"模拟Oracle数字格式逻辑的人也要注意。 REGEXP方法,请不要忘记考虑NLS_NUMERIC_CHARACTERS和NLS_TERRITORY。
答案 9 :(得分:1)
这是我查询所有非数字的查询:
Select myVarcharField
From myTable
where not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\.\d+)?$', '')
and not REGEXP_LIKE(myVarcharField, '^(-)?\d+(\,\d+)?$', '');
在我的领域,我。并且,遗憾的是十进制数不得不考虑到这一点,否则你只需要一个限制。
答案 10 :(得分:0)
好吧,您可以创建is_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调用的细节......
答案 11 :(得分:-1)
长度为10位的手机号码的功能,使用正则表达式从9,8,7开始
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;
答案 12 :(得分:-1)
我相信以下解决方案(基于上面的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;
我为什么这么说?
通过适当更改正则表达式,可以根据需要修改测试的数字子集。
它可以在SQL中使用,即从mytable中选择isInteger(myCol);因为它返回'F'的'T'而不是布尔值。
它可以在pl / sql中原生使用ie。 if isInteger(vMyValue)='T'然后....
它满足WNDS,WNPS纯度断言。
在我看来,它不依赖于“当其他人”接近结果确定时的过于宽泛的范围。
答案 13 :(得分:-1)
请注意,正则表达式或函数方法是several times slower than plain sql condition。
因此,一些具有有限适用性的启发式变通方法可以进行大量扫描。
如果您确定非数字值包含一些字母,则会出现solution:
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
答案 14 :(得分:-1)
如果condition为null则为数字
IF(rtrim(P_COD_LEGACY, '0123456789') IS NULL) THEN
return 1;
ELSE
return 0;
END IF;
答案 15 :(得分:-1)
您可以使用此示例
SELECT NVL((SELECT 1 FROM DUAL WHERE REGEXP_LIKE (:VALOR,'^[[:digit:]]+$')),0) FROM DUAL;
答案 16 :(得分:-1)
这是一个简单的方法:
SELECT
TEST_TABLE.*,
CASE WHEN
TRANSLATE(TEST_TABLE.TEST_COLUMN, 'a.,0123456789', 'a') IS NULL
THEN 'Y'
ELSE 'N'
END
AS IS_NUMERIC
FROM
(
-- DUMMY TEST TABLE
(SELECT '1' AS TEST_COLUMN FROM DUAL) UNION
(SELECT '1,000.00' AS TEST_COLUMN FROM DUAL) UNION
(SELECT 'xyz1' AS TEST_COLUMN FROM DUAL) UNION
(SELECT 'xyz 123' AS TEST_COLUMN FROM DUAL) UNION
(SELECT '.,' AS TEST_COLUMN FROM DUAL)
) TEST_TABLE
结果:
TEST_COLUMN IS_NUMERIC
----------- ----------
., Y
1 Y
1,000.00 Y
xyz 123 N
xyz1 N
5 rows selected.
当然,这可能不是最强大的方法。例如“。”被错误地标识为数字。但是,它非常简单,快速,并且可能非常适合完成此工作,具体取决于需要处理的实际数据值。
对于整数,我们可以简化Translate操作,如下所示:
TRANSLATE(TEST_TABLE.TEST_COLUMN, 'a0123456789', 'a') IS NULL
工作方式
从上面开始,请注意Translate
函数的语法为TRANSLATE(string, from_string, to_string)
。现在Translate
函数不能接受NULL
作为to_string
参数。
因此,通过将'a0123456789'
指定为from_string
,将'a'
指定为to_string
,会发生两件事:
a
被保留; 0
至9
替换为空,因为在to_string
中没有为它们指定任何替换。实际上,数字被丢弃。如果该操作的结果为NULL
,则表示它纯粹是数字开头。