PL/SQL Dynamic SQL: EXECUTE IMMEDIATE & DBMS_SQL
Sometimes the query you need to run doesn't exist until runtime. Learn how to dynamically construct and execute SQL statements on the fly, safely bind variables to prevent SQL injection, and choose between Native Dynamic SQL and the heavy-duty DBMS_SQL package.
1. Why Dynamic SQL?
Standard PL/SQL uses Static SQL. The compiler parses the SQL statements at compile-time, verifies the tables and columns exist, and bakes the execution plan into the package.
Dynamic SQL is built as a string (VARCHAR2 or CLOB) at runtime and executed on the fly. You need Dynamic SQL for three primary reasons:
- Executing DDL: You cannot run
TRUNCATE TABLEorDROP INDEXin static PL/SQL. - Dynamic Objects: The table name or column names are passed as parameters (e.g., querying a dynamically generated staging table).
- Dynamic Where Clauses: Building highly flexible search screens where the
WHEREclause changes drastically based on user input.
2. Native Dynamic SQL (EXECUTE IMMEDIATE)
Introduced in Oracle 8i, Native Dynamic SQL (NDS) made dynamic execution incredibly simple.
Basic Execution (DDL)
Using Bind Variables (Crucial for Security & Performance)
If you concatenate values directly into the SQL string, you risk SQL Injection and flood the Shared Pool with hard parses. Always use the USING clause.
You cannot bind object names
You cannot use bind variables for table names, column names, or keywords. SELECT * FROM :b_table will fail. You must concatenate object names, which requires strict validation to prevent injection.
Bulk Processing with NDS
You can combine Dynamic SQL with bulk operations for extreme performance.
3. The Heavy Lifter: DBMS_SQL
Before EXECUTE IMMEDIATE, developers had to use the DBMS_SQL package. It is vastly more complex, requiring you to manually open a cursor, parse the string, bind variables, execute, fetch, and close the cursor.
Why use it today? Method 4 Dynamic SQL.
If you are writing a query tool where you do not know the number of columns, their data types, or the number of bind variables until runtime, EXECUTE IMMEDIATE cannot handle it. DBMS_SQL provides the DESCRIBE_COLUMNS procedure to dynamically interrogate the result set shape.
4. Defeating SQL Injection
Dynamic SQL is the primary vector for SQL injection in PL/SQL.
Vulnerable Code:
v_sql := 'SELECT * FROM users WHERE username = ''' || p_user || '''';
If p_user is ' OR '1'='1, the query becomes SELECT * FROM users WHERE username = '' OR '1'='1'.
Fix 1: Bind Variables
v_sql := 'SELECT * FROM users WHERE username = :u';
EXECUTE IMMEDIATE v_sql USING p_user;
Fix 2: DBMS_ASSERT for Object Names
Since table names must be concatenated, use the DBMS_ASSERT package to verify the object actually exists before executing.
-- Will throw an error if p_table does not exist in the dictionary
v_safe_table := DBMS_ASSERT.SQL_OBJECT_NAME(p_table);
v_sql := 'TRUNCATE TABLE ' || v_safe_table;
EXECUTE IMMEDIATE v_sql;


