VillageSQL is a drop-in replacement for MySQL with extensions.
All examples in this guide work on VillageSQL. Install Now →
Creating a Stored Procedure
MySQL usesDELIMITER to change the statement terminator so the ; inside the procedure body doesn’t end the CREATE PROCEDURE statement early.
CALL:
Parameters
Procedures support three parameter modes:| Mode | Direction | Use case |
|---|---|---|
IN | Caller → procedure | Pass a value in |
OUT | Procedure → caller | Return a value out |
INOUT | Both | Pass in and modify |
OUT parameters:
Local Variables
Declare local variables withDECLARE at the top of the BEGIN...END block, before any other statements:
Control Flow
MySQL procedures support standard control flow constructs:Error Handling
UseDECLARE ... HANDLER to catch errors:
EXIT HANDLER stops the procedure when the condition fires. CONTINUE HANDLER lets the procedure keep running. RESIGNAL re-raises the error to the caller.
Raise your own errors with SIGNAL:
45000 is the SQLSTATE for “unhandled user-defined exception.”
Cursors
Cursors iterate over a result set row by row inside a procedure. Use them when you can’t express the logic as a set operation.NOT FOUND handler sets v_done when the cursor runs out of rows. Always close cursors before the procedure ends.
Stored Procedures vs Functions
| Stored Procedure | Stored Function | |
|---|---|---|
| Return value | Via OUT parameters or result sets | Single return value |
| Call syntax | CALL proc() | SELECT func() — used in expressions |
| Transactions | Can START TRANSACTION, COMMIT, ROLLBACK | Cannot modify transaction state |
| Result sets | Can return multiple result sets | Cannot return result sets |
| Use in SQL | Cannot be used in SELECT expressions | Can be used in SELECT, WHERE, etc. |
When to Use Stored Procedures
Stored procedures make sense when:- Enforcing business rules that must apply regardless of which application or user runs the query
- Reducing round trips for multi-step operations (complex batch jobs, data migrations)
- Granting users access to specific operations without exposing underlying tables (
GRANT EXECUTE ON PROCEDURE)
- The logic changes frequently — deployments require ALTER PROCEDURE or DROP/recreate
- Debugging is needed — no debugger, only SIGNAL-based logging
- Portability matters — stored procedure syntax is MySQL-specific
Frequently Asked Questions
Can a stored procedure return a result set?
Yes. AnySELECT inside a procedure that doesn’t use INTO sends a result set to the caller:
SELECT statements inside one procedure send multiple result sets. Most clients handle this but some ORMs don’t.
How do I see all stored procedures in a database?
Troubleshooting
| Problem | Solution |
|---|---|
ERROR 1064 on CREATE PROCEDURE | Missing DELIMITER change — the ; inside the body ended the statement early; wrap with DELIMITER $$ ... $$; DELIMITER ; |
ERROR 1172: Result consisted of more than one row | A SELECT ... INTO returned multiple rows — add a LIMIT 1 or fix the query to return a single row |
OUT parameter is NULL after CALL | The procedure didn’t assign to it — check all code paths reach the SET or SELECT INTO for that parameter |
ERROR 1193: Unknown system variable | Used SET @var (session variable) where DECLARE v_var (local variable) was needed, or vice versa |
| Procedure runs but returns no data | The result set SELECT is sending data through an extra layer (nested CALL) — bring the SELECT to the outermost procedure |

