今天在itpub上看到一个帖子,在删除表的时候出现问题:
SQL> drop table t4; drop table t4 * ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-01422: exact fetch returns more than requested number of rows
通常来说 drop table 失败的原因都是权限不足,但这次却报递归SQL出错,咋看让人摸不着头脑,随着版主的分析终于揭开了这个谜底——动了 dual 表。
以下是我的实验过程重演这个问题。
首先以一个测试用户(我这里是scott)创建一个普通表:
scott@ora10g(oracle01) SQL> create table tab01(f01 int); Table created.
以 sys 用户向 dual 插入一条数据,并提交:
sys@ora10g(oracle01) SQL> insert into dual values('Y');
1 row created.
sys@ora10g(oracle01) SQL> commit;
Commit complete.
由于一些内部的实现,以下是 dual 比较怪异的情况:
sys@ora10g(oracle01) SQL> select * from dual ;
D
-
X
sys@ora10g(oracle01) SQL> select count(*) from dual ;
COUNT(*)
----------
1
sys@ora10g(oracle01) SQL> begin
2 for x in (select * from dual) loop
3 dbms_output.put_line(x.dummy);
4 end loop;
5 end;
6 /
X
Y
可以看到只有匿名过程返回的结果才是两条数据。
此时以scott用户删除之前创建的测试表 tab01,即可触发帖子里面的问题:
scott@ora10g(oracle01) SQL> drop table tab01 ; drop table tab01 * ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-01422: exact fetch returns more than requested number of rows
做一个级别为12的10046跟踪,尝试找出问题:
scott@ora10g(oracle01) SQL> alter session set tracefile_identifier='drop_table_error'; Session altered. scott@ora10g(oracle01) SQL> alter session set events'10046 trace name context forever,level 12'; Session altered. scott@ora10g(oracle01) SQL> drop table tab01 ; drop table tab01 * ERROR at line 1: ORA-00604: error occurred at recursive SQL level 1 ORA-01422: exact fetch returns more than requested number of rows scott@ora10g(oracle01) SQL> alter session set events '10046 trace name context off';
经过 tkprof 处理后,可以找到为一个引用了 dual 的地方:
select dummy
from
dual where ora_dict_obj_type = 'TABLE'
......
......
Rows Row Source Operation
------- ---------------------------------------------------
2 FILTER (cr=212 pr=2 pw=0 time=32261 us)
2 TABLE ACCESS FULL DUAL (cr=3 pr=0 pw=0 time=0 us)
删除了 dual 表中“多余”行后却是:
select dummy
from
dual where ora_dict_obj_type = 'TABLE'
......
......
Rows Row Source Operation
------- ---------------------------------------------------
1 FILTER (cr=107 pr=0 pw=0 time=17082 us)
1 TABLE ACCESS FULL DUAL (cr=3 pr=0 pw=0 time=0 us)
当然 drop table 也没有再出错了。