我的列字段是varchar,并且包含数字和字符条目。
MyColumn将包含这些值,例如:
" 1.0"," AB"," A1"," 1"," 100"
如果用户键入" 1"在我的应用领域,我想做一个varchar搜索,匹配" 1"还有一个" 1.0"。
我无法做一个TO_NUMBER,因为有些数据不是数字,我会得到一个"而不是数字"异常。
我尝试使用OR子句检查myColumn是否为数字,然后再进行强制转换:
(trim(TRANSLATE(myColumn,'0123456789', ' ')) is null and TO_NUMBER(myColumn) = 1.0)
or myColumn = '1.0'
但我仍然得到ORA-01722:无效的数字,因为Oracle不会在另一方之前检查AND子句的一侧。
我试图"大概是"限制的两面:
case when trim(TRANSLATE(myColumn,'0123456789', ' ')) is null then TO_NUMBER(myColumn) else myColumn end
= case when trim(TRANSLATE(myColumn,'0123456789', ' ')) is null then 1.0 else '1.0' end;
但是我得到了ORA-00932不一致的数据类型
没有办法在oracle中执行条件where子句吗?
答案 0 :(得分:0)
您可以通过创建几个函数来确定值是否为数字来执行此操作:
create or replace function is_number (p_value varchar2)
return number
is
begin
return to_number(p_value);
exception
when value_error then
return null;
end;
/
create or replace function is_not_number (p_value varchar2)
return varchar2
is
v_num number;
begin
v_num := is_number(p_value);
return case when v_num is null then p_value
end;
end;
/
然后在适当的过滤谓词中使用这些函数:
with sample_data as (select '1.0' val from dual union all
select 'AB' val from dual union all
select 'A1' val from dual union all
select '1' val from dual union all
select '100' val from dual)
select val
from sample_data
where is_number(val) = 1;
VAL
---
1.0
1
with sample_data as (select '1.0' val from dual union all
select 'AB' val from dual union all
select 'A1' val from dual union all
select '1' val from dual union all
select '100' val from dual)
select val
from sample_data
where is_not_number(val) = 'AB';
VAL
---
AB
它不会非常高效,但是如果您要将任何旧数据推送到同一列中,那么您就不会充分利用数据库。
如果您不允许添加功能或更改基础数据结构(boo * {:-()),则可能会使用以下内容:
with sample_data as (select '1.0' val from dual union all
select 'AB' val from dual union all
select 'A1' val from dual union all
select '1' val from dual union all
select '100' val from dual union all
select '.100' val from dual union all
select '1e-10' val from dual union all
select '2.3e5' val from dual union all
select '-10' val from dual union all
select '+10' val from dual union all
select '+91.3e+2' val from dual union all
select '+-9.3e-2' val from dual union all
select '.1E5' val from dual union all
select '1.' val from dual union all
select '1.1.1' val from dual)
select val,
case when regexp_like(trim(val), '^(-|\+)?'|| -- checks for the presence of a positive or negative sign. This applies to all subsequent checks
'([[:digit:]]+(\.[[:digit:]]*$|$)'|| -- matches bog standard numbers with or without a decimal part (eg. 1, 1.01, 1.)
'|\.{1}[[:digit:]]+$'|| -- matches a number that has no digits before the decimal point (eg. .1)
'|[[:digit:]]+\.?[[:digit:]]*(e|E)(-|\+)?[[:digit:]]+$'|| -- matches scientific numbers starting with an integer with positive or negative numbers after the e/E (eg. 1e10, 1e-10)
'|\.[[:digit:]]+(e|E)(-|\+)?[[:digit:]]+$)' -- matches scientific numbers with starting with a decimal point (eg. .1e10, .1e-10)
) then to_number(val)
end num,
case when not regexp_like(trim(val), '^(-|\+)'||
'?([[:digit:]]+(\.[[:digit:]]*$|$)'||
'|\.{1}[[:digit:]]+$'||
'|[[:digit:]]+\.?[[:digit:]]*(e|E)(-|\+)?[[:digit:]]+$'||
'|\.[[:digit:]]+(e|E)(-|\+)?[[:digit:]]+$)') then val
end txt
from sample_data;
VAL NUM TXT
-------- ---------- --------
1.0 1
AB AB
A1 A1
1 1
100 100
.100 .1
1e-10 1.E-10
2.3e5 230000
-10 -10
+10 10
+91.3e+2 9130
+-9.3e-2 +-9.3e-2
.1e5 10000
1. 1
1.1.1 1.1.1
请注意,我可能错过了某些值为有效数字的情况;这是您必须手动复制to_number()
功能所需的价格。您必须手动添加丢失的案例。