使用原生动态SQL通过视图删除行时遇ORA错误求助
ORA-00933错误排查与存储过程修复
错误原因
你遇到的ORA-00933是因为单个EXECUTE IMMEDIATE无法直接执行多条独立SQL语句。你的动态SQL里同时写了CREATE VIEW和DELETE两条命令,Oracle会把整个字符串当作单条SQL解析,自然会报错命令未正确结束。
另外还有个小问题:SQL%ROWCOUNT要紧跟在执行删除语句的EXECUTE IMMEDIATE之后才能获取正确行数,原代码里的位置不对。
修复方案
方案1:拆分动态SQL,分别执行
把创建视图和删除操作拆成两个独立的EXECUTE IMMEDIATE调用:
create or replace procedure del_with_view (my_tab_name2 user_tables.table_name%type, row_count number) is temp_table user_tables.table_name%type; sql_create_view varchar2(1000); sql_delete varchar2(1000); begin temp_table := dbms_assert.sql_object_name(my_tab_name2); -- 单独执行创建视图语句 sql_create_view := 'create or replace view my_view as select rowid from '||temp_table||' fetch first '||row_count||' rows only'; execute immediate sql_create_view; -- 单独执行删除语句 sql_delete := 'delete from '||temp_table||' where rowid in (select rowid from my_view)'; execute immediate sql_delete; dbms_output.put_line('创建视图语句:'||sql_create_view); dbms_output.put_line('删除语句:'||sql_delete); dbms_output.put_line(sql%rowcount||' 行已删除'); end; /
方案2:去掉视图,直接子查询(更简洁高效)
其实没必要创建临时视图,直接在删除语句里用子查询获取要删除的rowid,减少不必要的对象创建:
create or replace procedure del_with_view (my_tab_name2 user_tables.table_name%type, row_count number) is temp_table user_tables.table_name%type; sql_delete varchar2(1000); begin temp_table := dbms_assert.sql_object_name(my_tab_name2); sql_delete := 'delete from '||temp_table||' where rowid in (select rowid from '||temp_table||' fetch first '||row_count||' rows only)'; execute immediate sql_delete; dbms_output.put_line('执行的删除语句:'||sql_delete); dbms_output.put_line(sql%rowcount||' 行已删除'); end; /
额外注意点
dbms_assert.sql_object_name的使用很正确,能有效防止SQL注入,建议保留。- 如果你的Oracle版本低于12c,不支持
FETCH FIRST语法,需要换成ROWNUM写法:select rowid from '||temp_table||' where rownum <= '||row_count
内容的提问来源于stack exchange,提问作者Matin Huseynli
相关产品推荐
相关产品推荐

