先看例子:
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Personal Oracle Database 10g Release 10.2.0.1.0 - Production
PL/SQL Release 10.2.0.1.0 - Production
CORE 10.2.0.1.0 Production
TNS for 32-bit Windows: Version 10.2.0.1.0 - Production
NLSRTL Version 10.2.0.1.0 - Production
SQL>
SQL> declare
2 v_x varchar2(10);
3 begin
4 select max('1')
5 into v_x
6 from dual;
7 end;
8 /
declare
v_x varchar2(10);
begin
select max('1')
into v_x
from dual;
end;
ORA-06502: PL/SQL: 数字或值错误 : 字符串缓冲区太小
ORA-06512: 在 line 5
可以看到,使用max时,出现了该异常。
开始看到这个现象的时候,以为是变量定义范围太小的缘故。但是从同事那边来看,如果是这么简单,应该他早就发现了。所以我想应该不能从这个方向去解决问题。所以我尝试使用直接字符串1来替换max中的内容,这样v_x这个变量的范围肯定可以容下这个字符串了。结果即在意料之外,又在意料之中。意料之外是1这样的字符串也抛出了异常。如果是a这样的字符,还有点道理。但是1却没有料到。意料之中是这个问题的确不像我之前所说的那么简单。
于是我考虑是不是max在plsql中取值的时候都是按照数字来转换的,而不会做默认的转换,只要遇到字符串就抛出该异常。因此我尝试用to_char转换:
SQL> declare
2 v_x varchar2(10);
3 begin
4 select max(to_char('1'))
5 into v_x
6 from dual;
7 end;
8 /
PL/SQL procedure successfully completed
发现是可以的。但是进一步的检查发现:
SQL> declare
2 v_x varchar2(10);
3 begin
4 select to_char(max('1'))
5 into v_x
6 from dual;
7 end;
8 /
PL/SQL procedure successfully completed
to_char放在外面也是可以的。这个就搞不懂了。经过google,发现这原来是oracle10g的一个bug,当max中的数据类型是char时就会抛出这个异常,但是如果是varchar2就不会有该异常,在9i上测试没有该问题。
转成varchar2后的测试:
SQL> declare
2 v_x varchar2(10);
3 begin
4 select max(cast('1' as varchar2(10)))
5 into v_x
6 from dual;
7 end;
8 /
PL/SQL procedure successfully completed
实际上to_char也是将对应的字符串转成varchar2。
该问题对应的bug#4458790