PL/SQL Exception Handling — Silent Data Loss, NO_DATA_FOUND
Missing FK triggers NO_DATA_FOUND in loop; WHEN OTHERS with ROLLBACK wipes prior insert — batch success, data lost.
- PL/SQL exception handling separates error logic from business logic using an EXCEPTION block
- Three categories: predefined (NO_DATA_FOUND), non-predefined (mapped via PRAGMA), and user-defined (business rule violations)
- Performance: unhandled exceptions cause implicit ROLLBACK, which is slower than explicit error responses
- Production insight: WHEN OTHERS THEN NULL silently kills errors — you'll debug blind for hours
- Biggest mistake: Using SELECT INTO without a NO_DATA_FOUND handler in batch jobs — whole transaction rolls back on missing rows
Think of PL/SQL Exception Handling as a powerful tool in your developer toolkit. Once you understand what it does and when to reach for it, everything clicks into place. Imagine you are operating a complex manufacturing assembly line. Without exception handling, a single jammed gear causes the entire factory to explode. With exception handling, the system detects the jam, safely pauses that specific machine, logs the error for the mechanic, and allows the rest of the factory to keep running or shuts down gracefully without losing progress.
PL/SQL Exception Handling is a fundamental concept in Database development. In the world of Oracle programming, an exception is an error condition that occurs during the execution of a block. Effective handling ensures that your application remains stable even when the database encounters unexpected data or system issues.
In this guide we'll break down exactly what PL/SQL Exception Handling is, why it was designed to separate error logic from business logic, and how to use it correctly in real projects.
By the end you'll have both the conceptual understanding and practical code examples to use PL/SQL Exception Handling with confidence.
What Is PL/SQL Exception Handling and Why Does It Exist?
PL/SQL Exception Handling is a core feature of PL/SQL. It was designed to solve a specific problem: unhandled errors causing transaction failure and messy stack traces for the end-user. It exists to provide a centralized 'EXCEPTION' block at the end of your code, keeping your main execution path clean. There are three categories: Predefined (like NO_DATA_FOUND), Non-predefined (standard Oracle errors mapped to names), and User-defined (business rule violations). This architecture allows for graceful recovery, customized error logging, and consistent transaction management via ROLLBACK.
Types of Exceptions: Predefined, Non-Predefined, and User-Defined
Oracle provides a set of predefined exceptions like NO_DATA_FOUND (ORA-01403), TOO_MANY_ROWS (ORA-01422), DUP_VAL_ON_INDEX (ORA-00001), and others. These are automatically raised when the corresponding Oracle error occurs. Non-predefined exceptions cover standard Oracle errors that don't have a built-in name — you map them using PRAGMA EXCEPTION_INIT. User-defined exceptions are declared with the EXCEPTION keyword and raised explicitly with RAISE or RAISE_APPLICATION_ERROR. The choice depends on the error's source: predefined for common Oracle errors, non-predefined for specific ORA codes you want a name for, user-defined for your application's business rules.
Exception Propagation and Scope
Exceptions propagate from inner blocks to outer blocks until caught or until they reach the outermost block and become unhandled, causing the program to terminate. If an exception is raised in the declarative section (e.g., a variable initialisation fails), it cannot be caught by the same block's EXCEPTION section — it propagates immediately to the enclosing block. Understanding scope is critical: each BEGIN-END block has its own exception section. An exception raised in an inner block that is not handled there will propagate to the outer block's EXCEPTION section. You can use nested blocks to isolate errors and continue processing while still maintaining transactional integrity.
RAISE vs RAISE_APPLICATION_ERROR: When to Use Each
RAISE is used to re-raise the current exception or explicitly raise a user-defined exception declared with EXCEPTION. It preserves the original error stack. RAISE_APPLICATION_ERROR is a built-in procedure that raises a user-defined Oracle error with a custom message and optional flag to keep the error stack. Use RAISE_APPLICATION_ERROR when you want to raise a new error with a specific code (between -20000 and -20999) and message, especially when the caller expects a numeric error code. For simple business rule violations, a user-defined exception with RAISE is cleaner. For errors that need to be caught by external applications (like Java via JDBC), RAISE_APPLICATION_ERROR is better because it provides a standard Oracle error.
Common Mistakes and How to Avoid Them
When learning PL/SQL Exception Handling, most developers hit the same set of gotchas. The most dangerous is the 'Silent Failure'—using WHEN OTHERS THEN NULL; which swallows the error and makes debugging impossible. Another is failing to ROLLBACK a failed transaction, leaving the database in an inconsistent state.
Knowing these in advance saves hours of debugging production outages and prevents data corruption.
Best Practices for Production-Ready Exception Handling
Beyond the basics, robust exception handling in production requires logging, transaction management, and consistent propagation. Create a central error logging procedure that captures SQLCODE, SQLERRM, backtrace (DBMS_UTILITY.FORMAT_ERROR_BACKTRACE), and timestamp. Use autonomous transactions for error logging so that log inserts survive a rollback. Always re-raise exceptions after logging unless the error is truly recoverable. For batch processing, use SAVEPOINT and ROLLBACK TO SAVEPOINT to isolate failed rows. Handle COM (Communication) and TIMEOUT_ON_RESOURCE separately from application errors.
- Autonomous transaction ensures the log persists even if the outer transaction rolls back.
- DBMS_UTILITY.FORMAT_ERROR_BACKTRACE gives the exact line number — essential for debugging.
- Always re-raise after logging unless the error is expected and recoverable.
- Use WHEN OTHERS THEN log_error(...); RAISE; as a universal pattern.
Silent Data Loss in a Nightly Batch Job
- Always handle NO_DATA_FOUND explicitly where it occurs — don't let it bubble up blindly.
- Never use ROLLBACK inside an exception handler in a loop unless you also re-raise or exit the loop.
- Use SAVEPOINTs inside iterative processing to isolate failures to a single row.
- Test batch jobs with intentionally missing data to verify exception scope behaviour.
Key takeaways
Common mistakes to avoid
3 patternsUsing 'WHEN OTHERS THEN NULL'
Not understanding exception propagation from the DECLARE section
Ignoring error handling in loops — failing to isolate row-level exceptions
Interview Questions on This Topic
What is the difference between SQLCODE and SQLERRM in an exception block?
Frequently Asked Questions
That's PL/SQL. Mark it forged?
3 min read · try the examples if you haven't