问题描述:
如上图所示,数据库中表v_person里的字段 person_code(verchar2(32))的数据有这样的几种形式。
查询条件:
person_code 范围:1 到 10
要完成的任务:
1. 返回结果一: 将表中所有person_code为纯数字的记录并且person_code的值在范围 1 到 10 之间的记录查出来,即:1,2,3,4,5,6,7,8,9,10。
2. 返回结果二:将表中所有person_code为“47-A”这样的形式,也就是说,“-”前面是纯数字的,并且,“-”前面的数字值在范围 1 到 10 之间的记录查出来,如:1-A,02-A等等。
在做的过程中,从失败到成功,所有用到的语句和出现的问题如下:
尝试一:
select t.person_code, t.person_name, t.org_Cname
from v_report_person t
where 1 = 1
and t.person_code >= '1'
and t.person_code <= '10'
and ((1 = 1 and length(t.person_code) >= length('1') and
length(t.person_code) <= length('10')) or
(1 = 1 and instr(t.person_code, '-') - 1 >= length('1') and
instr(t.person_code, '-') - 1 <= length('10')))
order by decode(instr(t.person_code, '-'),
0,
LENGTH(t.person_code),
instr(t.person_code, '-') - 1),
t.person_code;
这样的语句,返回的只有两条数据:person_code =1 和 person_code=10只有这两条。
因此,我明白了,这条语句它认为 2比10大,后来,我换数据尝试确实认证了这个想法。
尝试二:
select *
from v_report_person t
where FUN_ISNUMBER(t.person_code) != 0--所有person_code为纯数字的记录
and t.person_code >= '1'
and t.person_code <= '10'
and length(t.person_code) >= length('1')
and length(t.person_code) <= length('10')
ps:FUN_ISNUMBER代码:
--检查是否数字型
function FUN_ISNUMBER(
P_VALUE varchar2--输入参数
) return number is
LL_VALUE number;
begin
LL_VALUE := TO_NUMBER(P_VALUE);
return LL_VALUE;
exception when others then
return 0;------如果不是返回0
end FUN_ISNUMBER;
这样的尝,得到的仍是两条记录:person_code =1 和 person_code=10
以上是最主要的两种尝试,其他的试过to_number,convert,cast还有其他一些我能想到的方法。最终还是失败了。
select *
from v_report_person t
where PKG_BASE_UTIL.FUN_ISNUMBER(t.person_code) != 0
and to_number(t.person_code) >= 1
and to_nubmer(t.person_code )<= 10
and length(t.person_code) >= length('1')
and length(t.person_code) <= length('10')
这样尝试,报错:
搞了好几天,也没解决问题(
也许高手看了感觉再简单不过了,可是俺就不行了,要么怎么会有高手和菜鸟之说呢):
最后,我问了我一个朋友,和他讨论了半天,他也出了许多方式,最后他问了句:“你那个单引号,去掉了会报错吗?”
我就赶紧试了试,说实在话,我试了那么多次, to_number(t.person_code) >= 1 和 t.person_code >= '1' ,唯独没有试过 t.person_code >= 1
结果出来了,竟然出来了。
曾经那种思维定势,非要to_number(t.person_code) >= 1这样去比较,结果碰了钉子。
竟然因为一个“单引号”,在死坛中出不来。
症结一打开,很快,我就搞定了,我想要的结果:
select t.person_code,t.person_name,t.org_Cname from (select *
from v_report_person t
where (pkg_base_util.FUN_ISNUMBER(t.person_code) != 0
and t.person_code >= 1
and t.person_code <= 50
and length(t.person_code) >= length(1)
and length(t.person_code) <= length(50))
union all
select *from v_report_person t
where pkg_base_util.FUN_ISNUMBER(substr(t.person_code, 1,instr(t.person_code, '-') - 1)) != 0
and length(substr(t.person_code, 1,instr(t.person_code, '-') - 1)) >= length(1)
and length(substr(t.person_code, 1,instr(t.person_code, '-') - 1)) <= length(50)
and to_number(substr(t.person_code, 1,instr(t.person_code, '-') - 1))>=1
and to_number(substr(t.person_code, 1,instr(t.person_code, '-') - 1))<=50) t
order by decode(instr(t.person_code, '-'), 0, LENGTH(t.person_code),instr(t.person_code, '-') - 1),t.person_code;
我得到了我想要的结果如图:
1. 返回结果一: 将表中所有person_code为纯数字的记录并且person_code的值在范围 1 到 50 之间的记录查出来。
2. 返回结果二:将表中所有person_code为“47-A”这样的形式,也就是说,“-”前面是纯数字的,并且,“-”前面的数字值在范围 1 到 50 之间的记录查出来,如:1-A,02-A等等。
特记下这个过程,以便以后追忆。
后记:上面的语句还是不行,超过3位的就会出错,就是说把50变成100后就会出错,不解。
后来请高手解决了,答案补充如下:
select *
from t_md_person t
where (decode(FUN_ISNUMBER(t.person_code),
0,
decode(FUN_ISNUMBER(substr(t.person_code,
1,
instr(t.person_code,
'-') - 1)),
0,
-999999999999,
to_number(substr(t.person_code,
1,
instr(t.person_code, '-') - 1))),
to_number(t.person_code)) >= 1 and
decode(FUN_ISNUMBER(t.person_code),
0,
decode(FUN_ISNUMBER(substr(t.person_code,
1,
instr(t.person_code,
'-') - 1)),
0,
999999999999,
to_number(substr(t.person_code,
1,
instr(t.person_code, '-') - 1))),
to_number(t.person_code)) <= 100)
order by decode(instr(t.person_code, '-'),
0,
LENGTH(t.person_code),
instr(t.person_code, '-') - 1),
t.person_code;