Beruflich Dokumente
Kultur Dokumente
SQL>
SQL> -- Define procedure and execute them
SQL>
SQL> create table mytable ( x int );
Table created.
SQL>
SQL> create or replace procedure myProcecdure1 as
2 begin
3 for i in 1 .. 10000
4 loop
5 execute immediate 'insert into mytable values ( :x )' using i;
6 end loop;
7 end;
8 /
Procedure created.
SQL>
SQL> create or replace procedure myProcecdure2 as
2 begin
3 for i in 1 .. 10000
4 loop
5 execute immediate 'insert into mytable values ( '||i||')';
6 end loop;
7 end;
8 /
Procedure created.
SQL>
SQL> exec myProcecdure1;
SQL>
SQL> exec myProcecdure2;
SQL>
SQL>
SQL> drop table myTable;
Table dropped.
SQL>
Here are a few suggestion:
1. Where-ever possible you should use bind variables so you don't shoot
your
shared pool to pieces, so do it like this:
execute immediate 'insert into test values (:1, :2, :3)' USING 2, 'joe',
TO_DATE
('07-JUN-2005','DD-MON-YYYY')
2. To simplify your SQL and improve error handling, always put your
dymanic
SQL into a variable, then run the variable:
DECLARE
w_sql VARCHAR2(100) := 'insert into test values (:1, :2, :3)';
BEGIN
execute immediate w_sql USING 2, 'joe', TO_DATE('07-JUN-2005','DD-MON-
YYYY');
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error running sql: '||w_sql);
RAISE;
END;
Scott Hutchinson
Interact Analysis Ltd.
declare
type tab_char is table of varchar2(1) index by binary_integer;
t_char tab_char;
begin
for i in 1..26 loop
t_char(i) := chr(64 + i);
end loop;
forall i in 1..26
execute immediate
'begin
insert into test_forall_dyn (val) values(:1);
insert into test_forall_dyn (val) values(:1);
end;'
using t_char(i);
end;
/
Syntax
Description of the illustration execute_immediate_statement.gif
bind_argument
An expression whose value is passed to the dynamic SQL statement, or a variable that stores a
value returned by the dynamic SQL statement.
define_variable_name
dynamic_string
A string literal, variable, or expression that represents a single SQL statement or a PL/SQL
block. It must be of type CHAR or VARCHAR2, not NCHAR or NVARCHAR2.
INTO ...
Used only for single-row queries, this clause specifies the variables or record into which column
values are retrieved. For each value retrieved by the query, there must be a corresponding, type-
compatible variable or field in the INTO clause.
record_name
Used only for DML statements that have a RETURNING clause (without a BULK COLLECT clause),
this clause specifies the bind variables into which column values are returned. For each value
returned by the DML statement, there must be a corresponding, type-compatible variable in the
RETURNING INTO clause.
USING ...
Specifies a list of input and/or output bind arguments. The parameter mode defaults to IN.
Usage Notes
Except for multi-row queries, the dynamic string can contain any SQL statement (without the
final semicolon) or any PL/SQL block (with the final semicolon). The string can also contain
placeholders for bind arguments. You cannot use bind arguments to pass the names of schema
objects to a dynamic SQL statement.
You can place all bind arguments in the USING clause. The default parameter mode is IN. For
DML statements that have a RETURNING clause, you can place OUT arguments in the RETURNING
INTO clause without specifying the parameter mode, which, by definition, is OUT. If you use both
the USING clause and the RETURNING INTO clause, the USING clause can contain only IN
arguments.
At run time, bind arguments replace corresponding placeholders in the dynamic string. Every
placeholder must be associated with a bind argument in the USING clause and/or RETURNING INTO
clause. You can use numeric, character, and string literals as bind arguments, but you cannot use
Boolean literals (TRUE, FALSE, and NULL). To pass nulls to the dynamic string, you must use a
workaround. See "Passing Nulls to Dynamic SQL".
Dynamic SQL supports all the SQL datatypes. For example, define variables and bind arguments
can be collections, LOBs, instances of an object type, and refs. Dynamic SQL does not support
PL/SQL-specific types. For example, define variables and bind arguments cannot be Booleans or
index-by tables. The only exception is that a PL/SQL record can appear in the INTO clause.
You can execute a dynamic SQL statement repeatedly using new values for the bind arguments.
You still incur some overhead, because EXECUTE IMMEDIATE re-prepares the dynamic string
before every execution.
The string argument to the EXECUTE IMMEDIATE command cannot be one of the national
character types, such as NCHAR or NVARCHAR2.
Examples
DECLARE
sql_stmt VARCHAR2(200);
plsql_block VARCHAR2(500);
emp_id NUMBER(4) := 7566;
salary NUMBER(7,2);
dept_id NUMBER(2) := 50;
dept_name VARCHAR2(14) := 'PERSONNEL';
location VARCHAR2(13) := 'DALLAS';
emp_rec emp%ROWTYPE;
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE bonus (id NUMBER, amt NUMBER)';
sql_stmt := 'INSERT INTO dept VALUES (:1, :2, :3)';
EXECUTE IMMEDIATE sql_stmt USING dept_id, dept_name, location;
sql_stmt := 'SELECT * FROM emp WHERE empno = :id';
EXECUTE IMMEDIATE sql_stmt INTO emp_rec USING emp_id;
plsql_block := 'BEGIN emp_pkg.raise_salary(:id, :amt); END;';
EXECUTE IMMEDIATE plsql_block USING 7788, 500;
sql_stmt := 'UPDATE emp SET sal = 2000 WHERE empno = :1
RETURNING sal INTO :2';
EXECUTE IMMEDIATE sql_stmt USING emp_id RETURNING INTO salary;
EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :num'
USING dept_id;
EXECUTE IMMEDIATE 'ALTER SESSION SET SQL_TRACE TRUE';
END;
ORACLE
EXECUTE IMMEDIATE is the replacement for DBMS_SQL package from Oracle 8i onwards. It
parses and immediately executes a dynamic SQL statement or a PL/SQL block created on
the fly. Dynamically created and executed SQL statements are performance overhead,
EXECUTE IMMEDIATE aims at reducing the overhead and give better performance. It is also
easier to code as compared to earlier means. The error messages generated when using
this feature are more user friendly. Though DBMS_SQL is still available, it is advisable to
use EXECUTE IMMEDIATE calls because of its benefits over the package.
Usage tips
1. EXECUTE IMMEDIATE will not commit a DML transaction carried out and an explicit
commit should be done.
If the DML command is processed via EXECUTE IMMEDIATE, one needs to explicitly commit
any changes that may have been done before or as part of the EXECUTE IMMEDIATE itself.
If the DDL command is processed via EXECUTE IMMEDIATE, it will commit all previously
changed data.
2. Multi-row queries are not supported for returning values, the alternative is to use a
temporary table to store the records (see example below) or make use of REF cursors.
3. Do not use a semi-colon when executing SQL statements, and use semi-colon at the end
when executing a PL/SQL block.
4. This feature is not covered at large in the Oracle Manuals. Below are examples of all
possible ways of using Execute immediate. Hope it is handy.
5. For Forms Developers, this feature will not work in Forms 6i front-end as it is on PL/SQL
8.0.6.3.
begin
execute immediate 'set role all';
end;
declare
l_depnam varchar2(20) := 'testing';
l_loc varchar2(10) := 'Dubai';
begin
execute immediate 'insert into dept values (:1, :2, :3)'
using 50, l_depnam, l_loc;
commit;
end;
declare
l_cnt varchar2(20);
begin
execute immediate 'select count(1) from emp'
into l_cnt;
dbms_output.put_line(l_cnt);
end;
4. To call a routine dynamically: The bind variables used for parameters of the routine have
to be specified along with the parameter type. IN type is the default, others have to be
specified explicitly.
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;
5. To return value into a PL/SQL record type: The same option can be used for %rowtype
variables also.
declare
type empdtlrec is record (empno number(4),
ename varchar2(20),
deptno number(2));
empdtl empdtlrec;
begin
execute immediate 'select empno, ename, deptno ' ||
'from emp where empno = 7934'
into empdtl;
end;
6. To pass and retrieve values: The INTO clause should precede the USING clause.
declare
l_dept pls_integer := 20;
l_nam varchar2(20);
l_loc varchar2(20);
begin
execute immediate 'select dname, loc from dept where deptno = :1'
into l_nam, l_loc
using l_dept ;
end;
7. Multi-row query option. Use the insert statement to populate a temp table for this option.
Use the temporary table to carry out further processing. Alternatively, you may use REF
cursors to by-pass this drawback.
declare
l_sal pls_integer := 2000;
begin
execute immediate 'insert into temp(empno, ename) ' ||
' select empno, ename from emp ' ||
' where sal > :1'
using l_sal;
commit;
end;
EXECUTE IMMEDIATE is a much easier and more efficient method of processing dynamic
statements than could have been possible before. As the intention is to execute dynamic
statements, proper handling of exceptions becomes all the more important. Care should be
taken to trap all possible exceptions.