PLS-00103: Encountered the symbol "CREATE"
Categories:
Understanding and Resolving PLS-00103: Encountered the symbol "CREATE"

This article explains the common Oracle PLS-00103 error when encountering the "CREATE" symbol, its causes, and how to resolve it with practical examples.
The PLS-00103: Encountered the symbol "CREATE"
error is a common compilation error in Oracle PL/SQL. It typically indicates that the CREATE
statement, or a similar Data Definition Language (DDL) command, is being used in an inappropriate context within a PL/SQL block. PL/SQL is designed for procedural logic, while DDL statements are for defining or modifying database objects. This article will delve into why this error occurs and provide effective solutions.
Why PLS-00103 Occurs with CREATE
PL/SQL blocks (anonymous blocks, procedures, functions, packages, triggers) are primarily used for Data Manipulation Language (DML) operations (INSERT, UPDATE, DELETE, SELECT) and procedural logic. DDL statements like CREATE
, ALTER
, DROP
, TRUNCATE
, and GRANT
are transactional and implicitly commit any pending transactions. Directly embedding DDL statements within a PL/SQL block's executable section is generally not allowed because it violates the procedural nature and transaction management of PL/SQL.
flowchart TD A[PL/SQL Block Start] --> B{Executable Section} B --> C{DML Statements (Allowed)} B --> D{Procedural Logic (Allowed)} B --> E{DDL Statements (CREATE, ALTER, DROP)} E -- X --> F[PLS-00103 Error] C --> G[PL/SQL Block End] D --> G
Illustration of DDL statements causing PLS-00103 within a PL/SQL block
Common Scenarios and Solutions
The PLS-00103
error with CREATE
usually arises in a few specific situations. Understanding these scenarios is key to applying the correct solution.
Scenario 1: Attempting to Create an Object Directly in a PL/SQL Block
DECLARE
v_table_name VARCHAR2(30) := 'MY_TEMP_TABLE';
BEGIN
CREATE TABLE v_table_name (id NUMBER, name VARCHAR2(100));
END;
/
Incorrect attempt to create a table directly in PL/SQL
PLS-00103: Encountered the symbol "CREATE" when expecting one of the following: begin case declare exit for goto if loop mod null pragma raise return select update while with <an identifier> <a double-quoted delimited identifier> <a bind variable> << close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
Solution: Use Dynamic SQL with EXECUTE IMMEDIATE
To execute DDL statements from within a PL/SQL block, you must use dynamic SQL. This involves constructing the DDL statement as a string and then executing it using the EXECUTE IMMEDIATE
statement.
DECLARE
v_table_name VARCHAR2(30) := 'MY_TEMP_TABLE';
v_sql_stmt VARCHAR2(200);
BEGIN
v_sql_stmt := 'CREATE TABLE ' || v_table_name || ' (id NUMBER, name VARCHAR2(100))';
EXECUTE IMMEDIATE v_sql_stmt;
DBMS_OUTPUT.PUT_LINE('Table ' || v_table_name || ' created successfully.');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating table: ' || SQLERRM);
END;
/
Correct way to create a table using dynamic SQL
EXCEPTION WHEN OTHERS
) when using EXECUTE IMMEDIATE
for DDL, as errors in dynamic SQL are only caught at runtime.Scenario 2: Missing BEGIN...END
Block for Anonymous PL/SQL
Sometimes, the error can occur if you're trying to execute a CREATE
statement as part of a script that mixes DDL and PL/SQL, and the PL/SQL part isn't properly delimited.
CREATE OR REPLACE PROCEDURE my_proc
IS
BEGIN
NULL;
END;
/
CREATE TABLE another_table (col1 NUMBER); -- This line might cause issues if not handled correctly in a script
DECLARE
v_count NUMBER;
BEGIN
SELECT COUNT(*) INTO v_count FROM another_table;
END;
/
Example of mixed DDL and PL/SQL in a script
If you're running a script in SQL*Plus or SQL Developer, the CREATE TABLE
statement is a standalone DDL command and should be fine. However, if you're trying to embed it within a larger PL/SQL context (e.g., a package body that's not just DDL), or if the tool expects a single PL/SQL block, it can lead to this error.
Solution: Ensure Proper Delimitation and Context
When writing scripts, ensure that DDL statements are executed as separate commands outside of PL/SQL blocks, or use EXECUTE IMMEDIATE
if they must be inside. For creating stored procedures, functions, packages, etc., the CREATE OR REPLACE
statement itself is DDL, but its body is PL/SQL.
-- This is correct: CREATE OR REPLACE is DDL, the body is PL/SQL
CREATE OR REPLACE FUNCTION get_sysdate RETURN DATE
IS
BEGIN
RETURN SYSDATE;
END;
/
-- This is also correct: standalone DDL
CREATE TABLE my_data (id NUMBER, value VARCHAR2(50));
-- This is correct: anonymous PL/SQL block
BEGIN
DBMS_OUTPUT.PUT_LINE('Hello from PL/SQL');
END;
/
Correctly structured DDL and PL/SQL in a script
Best Practices for DDL in PL/SQL
While EXECUTE IMMEDIATE
allows DDL within PL/SQL, it should be used judiciously. Frequent DDL operations can lead to performance overhead due to recompilation and locking. Consider these best practices:
1. Minimize DDL in PL/SQL
If possible, perform DDL operations outside of PL/SQL blocks, especially for production environments. DDL is typically part of deployment scripts, not application logic.
2. Use EXECUTE IMMEDIATE
for Dynamic DDL
When dynamic DDL is absolutely necessary (e.g., creating temporary tables with dynamic names, altering columns based on metadata), use EXECUTE IMMEDIATE
.
3. Implement Robust Error Handling
Always wrap EXECUTE IMMEDIATE
calls in an exception block to catch and handle potential runtime errors gracefully.
4. Grant Necessary Privileges
The user executing the PL/SQL block must have the necessary DDL privileges (e.g., CREATE TABLE
, ALTER TABLE
) directly, not just through a role, for EXECUTE IMMEDIATE
to succeed.
5. Avoid Hardcoding Object Names
When using dynamic SQL, parameterize object names to prevent SQL injection vulnerabilities. While less critical for CREATE TABLE
, it's a good habit.
CREATE GLOBAL TEMPORARY TABLE
once, and then INSERT
into it within PL/SQL, rather than repeatedly CREATE
ing and DROP
ping tables dynamically.