Sie sind auf Seite 1von 11

Execute immediate for an insert statement

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;

PL/SQL procedure successfully completed.

SQL>
SQL> exec myProcecdure2;

PL/SQL procedure successfully completed.

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.

Quoting Joe Smith <joe_dba@xxxxxxxxxxx>:

> I am trying to insert records into a table through execute immediate.


The
> number datatypes go in with no problem. It is the varchar2 and date
formats
>
> that are giving me a problem.
>
>
> examples:
>
> desc tables test
> col1 number,
> col2 varchar2(30)
> col3 date
>
> execute immediate 'insert into test values ('|| 2 ||', '|| joe ||', '||
> 07-JUN-05 ||')';
>
>
> I have tried different ways to format the varchar2 and date datatype, but
> keeps giving me an error.
>
> How do I format these datatypes within an execute immediate?
>
> thanks.
create table test_forall_dyn (val varchar2(1));

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;
/

select count(*) from test_forall_dyn;

EXECUTE IMMEDIATE Statement


The EXECUTE IMMEDIATE statement executes a dynamic SQL statement or anonymous PL/SQL
block. You can use it to issue SQL statements that cannot be represented directly in PL/SQL, or
to build up statements where you do not know all the table names, WHERE clauses, and so on in
advance. For more information, see Chapter 7.

Syntax
Description of the illustration execute_immediate_statement.gif

Keyword and Parameter Description

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

A variable that stores a selected column value.

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

A user-defined or %ROWTYPE record that stores a selected row.

RETURNING INTO ...

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

The following PL/SQL block contains several examples of dynamic SQL:

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

March 17, 2003

EXECUTE IMMEDIATE option for Dynamic SQL and PL/SQL


by Amar Kumar Padhi

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.

Example of EXECUTE IMMEDIATE usage

1. To run a DDL statement in PL/SQL.

begin
execute immediate 'set role all';
end;

2. To pass values to a dynamic statement (USING clause).

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;

3. To retrieve values from a dynamic statement (INTO clause).

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;

if l_status != 'OK' then


dbms_output.put_line('error');
end if;
end;

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.

Das könnte Ihnen auch gefallen