Dynamic SQL
Dynamic SQL
Dynamic SQL enables you to write programs that reference SQL statements whose full text is not known
until runtime. Before discussing dynamic SQL in detail, a clear definition of static SQL may provide a good
starting point for understanding dynamic SQL. Static SQL statements do not change from execution to
execution. The full text of static SQL statements are known at compilation, which provides the following
benefits:
Successful compilation verifies that the SQL statements reference valid database objects.
Successful compilation verifies that the necessary privileges are in place to access the database
objects.
Performance of static SQL is generally better than dynamic SQL.
Because of these advantages, you should use dynamic SQL only if you cannot use static SQL to
accomplish your goals, or if using static SQL is cumbersome compared to dynamic SQL. However, static
SQL has limitations that can be overcome with dynamic SQL. You may not always know the full text of
the SQL statements that must be executed in a PL/SQL procedure. Your program may accept user input
that defines the SQL statements to execute, or your program may need to complete some processing
work to determine the correct course of action. In such cases, you should use dynamic SQL.
Dynamic SQL also lets you execute data definition language (DDL) statements and other SQL statements
that are not supported in purely static SQL programs.
Dynamic SQL:
Is a SQL statement that contains variables that can change during runtime
Is a SQL statement with placeholders and is stored as a character string
Enables general-purpose code to be written
Enables data-definition, data-control, or sessioncontrol statements to be written and executed from
PL/SQL
Is written using either DBMS_SQL or native dynamic SQL
To process most native dynamic SQL statements, you use the EXECUTE IMMEDIATE statement. To
process a multi-row query (SELECT statement), you use OPEN-FOR, FETCH, and CLOSE statements.
The DBMS_SQL package is a PL/SQL library that offers an API to execute SQL statements dynamically.
The DBMS_SQL package has procedures to open a cursor, parse a cursor, supply binds, and so on.
Programs that use the DBMS_SQL package make calls to this package to perform dynamic SQL
operations.
The following sections provide detailed information about the advantages of both methods.
1
Dynamic SQL
By Muhammad Raheem [email protected]
Advantages of Native Dynamic SQL
Native dynamic SQL provides the following advantages over the DBMS_SQL package:
With the DBMS_SQL package you must call many procedures and functions in a strict sequence, making
even simple operations require a lot of code. You can avoid this complexity by using native dynamic SQL
instead.
The following table illustrates the difference in the amount of code required to perform the same operation
using the DBMS_SQL package and native dynamic SQL.
-- supply binds
dbms_sql.bind_variable
(cur_hdl, ':deptno', deptnumber);
dbms_sql.bind_variable
(cur_hdl, ':dname', deptname);
dbms_sql.bind_variable
(cur_hdl, ':loc', location);
-- execute cursor
rows_processed :=
dbms_sql.execute(cur_hdl);
-- close cursor
dbms_sql.close_cursor(cur_hdl);
END;
/
SHOW ERRORS;
2
Dynamic SQL
By Muhammad Raheem [email protected]
Native dynamic SQL bundles the statement preparation, binding, and execution steps into a single
operation, which minimizes the data copying and procedure call overhead and improves performance.
The DBMS_SQL package is based on a procedural API and incurs high procedure call and data copy
overhead. Each time you bind a variable, the DBMS_SQL package copies the PL/SQL bind variable into
its space for use during execution. Each time you execute a fetch, the data is copied into the space
managed by the DBMS_SQL package and then the fetched data is copied, one column at a time, into the
appropriate PL/SQL variables, resulting in substantial overhead.
For example, the following native dynamic SQL code does not use bind variables:
CREATE OR REPLACE PROCEDURE del_dept (
my_deptno dept.deptno%TYPE) IS
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = ' || to_char
(my_deptno);
END;
/
SHOW ERRORS;
For each distinct my_deptno variable, a new cursor is created, causing resource contention and poor
performance. Instead, bind my_deptno as a bind variable:
CREATE OR REPLACE PROCEDURE del_dept (
my_deptno dept.deptno%TYPE) IS
BEGIN
EXECUTE IMMEDIATE 'DELETE FROM dept WHERE deptno = :1' USING my_deptno;
END;
/
SHOW ERRORS;
Here, the same cursor is reused for different values of the bind my_deptno, improving performance and
scalabilty.
In the following example, the rows from a query are fetched into the emp_rec record:
DECLARE
TYPE EmpCurTyp IS REF CURSOR;
c EmpCurTyp;
emp_rec emp%ROWTYPE;
3
Dynamic SQL
By Muhammad Raheem [email protected]
stmt_str VARCHAR2(200);
e_job emp.job%TYPE;
BEGIN
stmt_str := 'SELECT * FROM emp WHERE job = :1';
-- in a multi-row query
OPEN c FOR stmt_str USING 'MANAGER';
LOOP
FETCH c INTO emp_rec;
EXIT WHEN c%NOTFOUND;
END LOOP;
CLOSE c;
-- in a single-row query
EXECUTE IMMEDIATE stmt_str INTO emp_rec USING 'PRESIDENT';
END;
/
DBMS_SQL Supports Multiple Row Updates and Deletes with a RETURNING Clause
The DBMS_SQL package supports statements with a RETURNING clause that update or delete multiple
rows. Native dynamic SQL only supports a RETURNING clause if a single row is returned.
Native dynamic SQL prepares a SQL statement each time the statement is used, which typically involves
parsing, optimization, and plan generation. Although the extra prepare operations incur a small
performance penalty, the slowdown is typically outweighed by the performance benefits of native dynamic
SQL.
4
Dynamic SQL
By Muhammad Raheem [email protected]
Querying Using Dynamic SQL: Example
The following example includes a dynamic query statement with one bind variable (:jobname) and two
select columns (ename and sal):
stmt_str := 'SELECT ename, sal FROM emp WHERE job = :jobname';
This example queries for employees with the job description SALESMAN in the job column of the emp
table. The following table shows sample code that accomplishes this query using the DBMS_SQL
package and native dynamic SQL.
rows_processed :=
dbms_sql.execute(cur_hdl); --
execute
LOOP
-- fetch a row
IF dbms_sql.fetch_rows(cur_hdl) > 0 then
-- <process data>
ELSE
EXIT;
END IF;
END LOOP;
dbms_sql.close_cursor(cur_hdl); -- close
cursor
END;
5
Dynamic SQL
By Muhammad Raheem [email protected]
This example inserts a new row for which the column values are in the PL/SQL variables deptnumber,
deptname, and location. The following table shows sample code that accomplishes this DML operation
using the DBMS_SQL package and native dynamic SQL.
DML Operation Using the DBMS_SQL Package and Native Dynamic SQL
DBMS_SQL DML Operation Native Dynamic SQL DML Operation
DECLARE DECLARE
stmt_str VARCHAR2(200); stmt_str VARCHAR2(200);
cur_hdl NUMBER; deptnumber NUMBER := 99;
deptnumber NUMBER := 99; deptname VARCHAR2(20);
deptname VARCHAR2(20); location VARCHAR2(10);
location VARCHAR2(10); BEGIN
rows_processed NUMBER; stmt_str := 'INSERT INTO
BEGIN dept_new VALUES
stmt_str := 'INSERT INTO dept_new VALUES (:deptno, :dname, :loc)';
(:deptno, :dname, :loc)'; EXECUTE IMMEDIATE stmt_str
cur_hdl := DBMS_SQL.OPEN_CURSOR; USING deptnumber, deptname,
DBMS_SQL.PARSE( location;
cur_hdl, stmt_str, DBMS_SQL.NATIVE); END;
-- supply binds /
DBMS_SQL.BIND_VARIABLE
(cur_hdl, ':deptno', deptnumber);
DBMS_SQL.BIND_VARIABLE
(cur_hdl, ':dname', deptname);
DBMS_SQL.BIND_VARIABLE
(cur_hdl, ':loc', location);
rows_processed :=
dbms_sql.execute(cur_hdl);
-- execute
DBMS_SQL.CLOSE_CURSOR(cur_hdl); -- close
END;
/
The following table shows sample code that accomplishes this operation using both the DBMS_SQL
package and native dynamic SQL.
DML Returning Operation Using the DBMS_SQL Package and Native Dynamic SQL
6
Dynamic SQL
By Muhammad Raheem [email protected]
If you have an application that uses OCI, Pro*C/C++, or Pro*COBOL to execute dynamic SQL, you
should consider switching to native dynamic SQL inside PL/SQL stored procedures and functions. The
network round-trips required to perform dynamic SQL operations from client-side applications might hurt
performance. Stored procedures can reside on the server, eliminating the network overhead. You can call
the PL/SQL stored procedures and stored functions from the OCI, Pro*C/C++, or Pro*COBOL application.
7
Dynamic SQL
By Muhammad Raheem [email protected]
Although you can enumerate each field of a PL/SQL record when inserting or updating rows in a table,
the resulting code is not especially readable or maintainable. Instead, you can use PL/SQL records
directly in these statements. The most convenient technique is to declare the record using a %ROWTYPE
attribute, so that it has exactly the same fields as the SQL table.
DECLARE
emp_rec emp%ROWTYPE;
BEGIN
emp_rec.eno := 1500;
emp_rec.ename := 'Steven Hill';
emp_rec.sal := '40000';
-- A %ROWTYPE value can fill in all the row fields.
INSERT INTO emp VALUES emp_rec;
Although this technique helps to integrate PL/SQL variables and types more closely with SQL DML
statements, you cannot use PL/SQL records as bind variables in dynamic SQL statements.