MySQL DECLARE CONDITION MySQL · Error Handling · DECLARE CONDITION

MySQL DECLARE CONDITION

Master MySQL DECLARE CONDITION for naming error codes and SQLSTATE values — make stored procedure code self-documenting. Covers the syntax, common error codes worth naming (1051, 1062, 1146, 1452), the strict declaration order (variables → conditions → cursors → handlers), and worked examples with multiple named conditions.

When a SQL statement fails or produces a warning inside a stored program, MySQL identifies what happened with one of two things: a MySQL error code (like 1051) or an SQLSTATE value (a 5-character string like '42S02'). These work fine for the database, but they're cryptic for humans reading the code. Was 1051 "unknown table", "deadlock", or "out of disk space"? You'd have to look it up.

The DECLARE ... CONDITION statement lets you give an error code a meaningful name — unknown_table, duplicate_key, foreign_key_violation. Then your handlers reference the name instead of the code, making the procedure self-documenting.

DECLARE condition_name CONDITION FOR condition_value;

Where condition_value is one of:

FormExample
A MySQL error code (integer)FOR 1051
An SQLSTATE valueFOR SQLSTATE '42S02'
SQLSTATE with optional VALUE keywordFOR SQLSTATE VALUE '42S02'

The DECLARE ... CONDITION statement only names a condition — it doesn't react to one. You still need a separate DECLARE ... HANDLER (covered on the next page) to actually do something when the condition fires.

⚠️ DECLARE order rule, restated: All DECLAREs in a BEGIN ... END block must come before any other statement, in this strict order:
  1. Local variables
  2. Conditions (DECLARE name CONDITION FOR ...;)
  3. Cursors
  4. Handlers (DECLARE HANDLER FOR ...;)
A condition declared after a handler that references it is a syntax error. Conditions are like cursors — they're declared up front, then referenced by other declarations.

Compare the two snippets below. They behave identically, but the second is much clearer:

MySQL — Without named condition (cryptic)
DECLARE CONTINUE HANDLER FOR 1051
BEGIN
    -- handler body
END;
MySQL — With named condition (self-documenting)
DECLARE unknown_table CONDITION FOR 1051;

DECLARE CONTINUE HANDLER FOR unknown_table
BEGIN
    -- handler body
END;

The cost is two extra lines; the benefit is that anyone reading the code learns immediately that this handler catches the "unknown table" error. Useful when you have several handlers in one procedure and need to keep track of what each one does.

Error codeSQLSTATEMeaningSuggested name
105142S02Unknown tableunknown_table
106223000Duplicate entry for keyduplicate_key
114642S02Table doesn't existmissing_table
121623000Foreign key violation (parent missing)fk_parent_missing
121723000Cannot delete: foreign key reference existsfk_referenced
126422003Out of range for columnvalue_out_of_range
1366HY000Incorrect value for column typebad_value
145223000Cannot add or update: foreign key constraint failsfk_violation
Example 1 — A Procedure with a Named Unknown-Table Condition

Build a procedure that takes a table name as input and returns its rows via dynamic SQL. If the table doesn't exist, the named condition catches the error gracefully:

MySQL — Named condition + handler
DROP PROCEDURE IF EXISTS GetData;

DELIMITER $$

CREATE PROCEDURE GetData(IN tbl_name VARCHAR(255))
    READS SQL DATA
BEGIN
    -- 1. Variables (none here)
    -- 2. Named conditions
    DECLARE unknown_table CONDITION FOR 1051;

    -- 3. Handlers
    DECLARE EXIT HANDLER FOR unknown_table
    BEGIN
        SELECT CONCAT('Table not found: ', tbl_name) AS error_message;
    END;

    -- Build and run the dynamic query
    SET @sql_query = CONCAT('SELECT * FROM ', tbl_name);
    PREPARE stmt FROM @sql_query;
    EXECUTE stmt;
    DEALLOCATE PREPARE stmt;
END$$

DELIMITER ;

Try it with an existing table — note this assumes the employees table from earlier chapters is loaded:

MySQL — Existing table
CALL GetData('employees');
OUTPUT
mysql — GetData('employees')
mysql>CALL GetData('employees');
+-------------+------------+-----------+----------+---------------+
| employee_id | first_name | last_name | salary | department_id |
+-------------+------------+-----------+----------+---------------+
| 100 | Steven | King | 24000.00 | 9 |
| 101 | Neena | Kochhar | 17000.00 | 9 |
| ... (8 more rows) |
+-------------+------------+-----------+----------+---------------+
10 rows in set (0.00 sec)

Now try a table that doesn't exist:

MySQL — Missing table
CALL GetData('abc');
OUTPUT
mysql — GetData('abc')
mysql>CALL GetData('abc');
+-------------------------+
| error_message |
+-------------------------+
| Table not found: abc |
+-------------------------+
1 row in set (0.00 sec)

Without the handler, the procedure would have terminated with raw error 1051. The handler catches the named condition and returns a friendly message instead.

Example 2 — Multiple Named Conditions in One Procedure

You can declare several conditions and handle each differently. Useful when one procedure needs to recognize multiple specific errors:

MySQL — Multiple named conditions
DROP PROCEDURE IF EXISTS SafeInsertUser;

DELIMITER $$

CREATE PROCEDURE SafeInsertUser(IN p_username VARCHAR(50),
                                IN p_email    VARCHAR(50))
    MODIFIES SQL DATA
BEGIN
    -- Named conditions
    DECLARE duplicate_key   CONDITION FOR 1062;
    DECLARE bad_value       CONDITION FOR 1366;
    DECLARE generic_error   CONDITION FOR SQLEXCEPTION;

    -- Specific handlers (order doesn't matter; MySQL picks the most specific)
    DECLARE EXIT HANDLER FOR duplicate_key
        SELECT 'Username already exists' AS error_message;

    DECLARE EXIT HANDLER FOR bad_value
        SELECT 'Invalid value for one or more columns' AS error_message;

    -- Catch-all
    DECLARE EXIT HANDLER FOR generic_error
        SELECT 'Unexpected database error' AS error_message;

    INSERT INTO users (username, email) VALUES (p_username, p_email);
    SELECT 'User created' AS status;
END$$

DELIMITER ;

This shows the pattern — each named condition gets its own targeted handler, and the generic_error handler catches anything else. We'll go deeper into handler matching on the next page.

You can declare a named condition for either form. Quick guidance:

Use the MySQL error code (1051) when…Use SQLSTATE ('42S02') when…
You want to handle a specific MySQL errorYou want to handle a class of related errors across systems
You're sure you'll only target MySQLYour code should be portable to other ANSI SQL databases
The exact error matters (e.g. only "table not found", not other 42S02 errors)You want to catch any error in a category (e.g. all integrity violations)
💡 SQLSTATE classes worth knowing:
  • '01...' — warnings (matched by SQLWARNING shorthand)
  • '02...' — no-data conditions (matched by NOT FOUND shorthand)
  • '00...' — success (no error)
  • Everything else — exceptions (matched by SQLEXCEPTION shorthand)
You'll see SQLWARNING, NOT FOUND, and SQLEXCEPTION a lot in handlers — they're built-in shorthands for whole SQLSTATE classes, so you don't need to declare named conditions for them.
  1. Use named conditions when an error code appears multiple times in the same procedure — DRY principle, single point of update.
  2. Pick names that describe the meaning, not the code. duplicate_key beats err_1062.
  3. Declare conditions before handlers — MySQL's strict declaration order requires it.
  4. Prefer SQLSTATE over numeric codes when working in code that might run on multiple databases or where you want to catch a category rather than a single error.
  5. Combine with handlers from the next page — DECLARE CONDITION on its own does nothing; you need DECLARE HANDLER to react to the condition.
  • DECLARE condition_name CONDITION FOR condition_value; assigns a meaningful name to a MySQL error code or SQLSTATE value.
  • The condition value can be either a numeric MySQL error code (1051) or an SQLSTATE string ('42S02').
  • Named conditions don't react to errors on their own — they're referenced by DECLARE HANDLER statements, covered on the next page.
  • Declaration order is strict: variables → conditions → cursors → handlers.
  • Use named conditions to make procedure code self-documenting; DECLARE EXIT HANDLER FOR unknown_table reads better than DECLARE EXIT HANDLER FOR 1051.