这篇文章介绍了Oracle中执行动态SQL的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
在一般的sql操作中,sql语句基本上都是固定的,如: SELECT t.empno,t.ename FROM scott.emp t WHERE t.deptno = 20;
但有的时候,从应用的需要或程序的编写出发,都可能需要用到动态SQl,如:
当 from 后的表 不确定时,或者where 后的条件不确定时,都需要用到动态SQL。
使用execute immediate语句可以处理包括ddl(create、alter和drop)、DCL(grant、revoke)、DML(insert、update、delete)以及单行select语句。
execute immediate语句:
- execute immediate dynamic_string
- [into {define_variable[,define_variable]…|record}]
- [using [in|out|in out] bind_argument[,[in|out|in out]bind_argument]…]
- [{returning|return} into bind_argument[, bind_argument]…]
不能使用into和using子句。
- begin
-
- execute immediate 'create table ma_org(org_codevarchar2(20),org_name varchar2(254))';
- execute immediate 'drop table ma_org';
- end;
如果dml语句包含占位符,那么在execute immediate语句之后必须要带有using子句;
- declare
- orgcode varchar2(10);
- orgname varchar2(254);
- begin
- orgcode := 1200;
- execute immediate 'select org_name fromma_org
- where org_code = :X'
- into orgname
- using orgcode;
- dbms_output.put_line(orgname);
- end;
- declare
- l_cnt varchar2(20);
- begin
- execute immediate 'select count(1) from emp'
- into l_cnt;
- dbms_output.put_line(l_cnt);
- end;
- declare
- l_routin varchar2(100) := 'gen2161.get_rowcnt';
- l_tblnam varchar2(20) := 'emp';
- l_cnt number;
- l_status varchar2(200);
- begin
- execute immediate 'begin ' || l_routin || '(:2, :3, :4); end;'
- using in l_tblnam, out l_cnt, in out l_status;
-
- if l_status != 'OK' then
- dbms_output.put_line('error');
- end if;
- end;
如果dml语句带有returning子句,那么在execute immediate语句之后必须带有returning into子句,并且此时只能处理作用的单行上的dml语句,如果dml语句作用在多行上,则必须使用bulk子句。
- declare
- orgcode varchar2(10);
- orgname varchar2(254);
- rname varchar2(254);
- begin
- orgcode := '1200';
- orgname := '天津市分行';
- execute immediate 'update ma_org set org_name=:X
- where org_code = :Y returning org_name into :rname'
- using orgname, orgcode
- returning into rname;
- dbms_output.put_line(orgname);
- end;
通过bulk collect减少loop处理的开销
采用bulk collect可以将查询结果一次性地加载到collections中。
而不是通过cursor一条一条地处理。
可以在select into,fetch into,returning into语句使用bulk collect。
注意在使用bulk collect时,所有的into变量都必须是collections.
举几个简单的例子:
- --在select into语句中使用bulk collect
- DECLARE
- TYPE SalList IS TABLE OF emp.sal%TYPE;
- sals SalList;
- BEGIN
- -- Limit the number of rows to 100.
- SELECT sal BULK COLLECT INTO sals FROM emp
- WHERE ROWNUM <= 100;
- -- Retrieve 10% (approximately) of the rows in the table.
- SELECT sal BULK COLLECT INTO sals FROM emp SAMPLE 10;
- END;
- /
- --在fetch into中使用bulk collect
- DECLARE
- TYPE DeptRecTab IS TABLE OF dept%ROWTYPE;
- dept_recs DeptRecTab;
- CURSOR c1 IS
- SELECT deptno, dname, loc FROM dept WHERE deptno > 10;
- BEGIN
- OPEN c1;
- FETCH c1 BULK COLLECT INTO dept_recs;
- END;
- /
- --在returning into中使用bulk collect
- CREATE TABLE emp2 AS SELECT * FROM employees;
- DECLARE
- TYPE NumList IS TABLE OF employees.employee_id%TYPE;
- enums NumList;
- TYPE NameList IS TABLE OF employees.last_name%TYPE;
- names NameList;
- BEGIN
- DELETE FROM emp2 WHERE department_id = 30
- RETURNING employee_id, last_name BULK COLLECT INTO enums, names;
- dbms_output.put_line('Deleted ' || SQL%ROWCOUNT || ' rows:');
- FOR i IN enums.FIRST .. enums.LAST
- LOOP
- dbms_output.put_line('Employee #' || enums(i) || ': ' || names(i));
- END LOOP;
- END;
- /
- DROP TABLE emp2;
oracle通过使用bulk collect into子句处理动态sql中的多行查询可以加快处理速度,从而提高应用程序的性能。当使用bulk子句时,集合类型可以是plsql所支持的索引表、嵌套表和varray,但集合元素必须使用sql数据类型。在oracle9i以后,有三种语句支持bulk子句,execute immediate,fetch和forall。
- DECLARE
- TYPE ref_cur IS REF CURSOR;
- rc ref_cur;
- emprow emp%ROWTYPE;
- v_sql VARCHAR2(100):= 'select * from emp where deptno = :x'; --动态执行的SQL语句
- BEGIN
- OPEN rc FOR v_sql USING 30; --打开游标,绑定执行的SQL语句,并传递参数
- LOOP
- FETCH rc INTO emprow;
- EXIT WHEN rc%NOTFOUND;
- dbms_output.put_line('name:'||emprow.ename||' sal:'||emprow.sal);
- END LOOP;
- CLOSE rc;
- END;
示例:
- declare
- type org_table_type is table of ma_org%rowtype;
- org_table org_table_type;
- v_orgcode varchar2(20);
- begin
- v_orgcode := '%00%';
- execute immediate 'select * from ma_org where org_code like:v_orgcode' bulk collect into org_table
- using v_orgcode;
- for i in 1..org_table.count
- loop
- dbms_output.put_line(org_table(i).org_code||','||org_table(i).org_name);
- end loop;
- end;
示例:
- declare
- type type_org_code is table of ma_org.org_code%type;
- type type_org_name is table of ma_org.org_name%type;
- v_orgcode type_org_code;
- v_orgname type_org_name;
- begin
- v_orgcode := type_org_code('1100','1200');
- forall i in 1..v_orgcode.count
- execute immediate 'update ma_org set org_name = org_code||org_namewhere org_code = :p1 returning org_name into :p2'
- using v_orgcode(i)
- returning bulk collect into v_orgname;
- for i in v_orgname.first..v_orgname.last
-
- loop
- dbms_output.put_line(v_orgname(i));
- end loop;
- end;
到此这篇关于Oracle中执行动态SQL的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持脚本之家。