Stored procedures
DELIMITER, IN/OUT parameters, variables, IF/CASE, loops, cursors and error handlers.
A stored procedure is a named block of SQL statements saved inside the database, which you run with CALL. Procedures can take parameters, use variables, branch, loop and handle errors. Teams use them to bundle multi-step operations into one call, enforce business rules close to the data and reduce network round trips.
Your first procedure#
Why DELIMITER? The procedure body contains semicolons. Normally the mysql client sends a statement to the server as soon as it sees ;, which would cut the CREATE PROCEDURE in half. DELIMITER $$ temporarily makes $$ the end-of-statement marker, and DELIMITER ; switches back. DELIMITER is a client command: GUI tools and application drivers send the whole statement at once and don't need it.
Parameters: IN, OUT and INOUT#
IN(the default): a value passed in.OUT: the procedure sets it and the caller reads it afterwards.INOUT: both.
@t and @n are user variables: session-wide and untyped, written with an @. SELECT ... INTO stores a query's single-row result into variables.
Local variables, IF and CASE#
Inside BEGIN ... END, declare local variables with DECLARE (at the top of the block) and assign them with SET or SELECT ... INTO:
(When SELECT ... INTO finds no row, the variable keeps its value, which is NULL here, and MySQL issues a "No data" warning.) Stored programs also have a CASE ... WHEN ... THEN ... END CASE statement for multi-way branching.
Loops#
MySQL has three loop forms: WHILE ... DO ... END WHILE, REPEAT ... UNTIL ... END REPEAT and labelled LOOP ... END LOOP (exited with LEAVE label, or skipped ahead with ITERATE label):
Remember that SQL is set-based. A single INSERT ... SELECT (or a recursive CTE) is almost always faster than a loop that inserts one row at a time. Use loops when the steps really are procedural.
Transactions and error handling#
Now a realistic procedure: an atomic money transfer that validates its input, uses a transaction, and rolls back on any error.
Only the valid transfer went through. The failing ones were rolled back completely, and the caller still received each error. Prefixing parameters with p_ (and local variables with v_) is a good habit: a parameter named like a column (amount, id) silently shadows that column inside queries, and some names clash with SQL syntax. For example, a variable called names fails because SET names = ... looks like the SET NAMES statement.
DECLARE ... HANDLER FOR conditioncatches errors. Conditions can beSQLEXCEPTION,SQLWARNING,NOT FOUND, a specific error number (FOR 1062) or anSQLSTATE.- An
EXIThandler leaves the block after running. ACONTINUEhandler carries on with the next statement. SIGNAL SQLSTATE '45000'raises your own error ('45000' means "unhandled user-defined exception").RESIGNALre-raises the current one.GET DIAGNOSTICS CONDITION 1 @msg = MESSAGE_TEXT;reads the error details inside a handler.
Cursors: row-by-row processing#
A cursor walks through a query's result one row at a time. A NOT FOUND handler tells you when the rows run out:
Declarations must come in this order: variables, then cursors, then handlers. (In real code, GROUP_CONCAT does this example in one line. Reach for cursors only when each row needs procedural work.)
Managing procedures#
There's no ALTER for a procedure's body. Drop it and create it again (or use CREATE PROCEDURE IF NOT EXISTS in 8.0.29+). Keep the source in version control like any other code. Users need the EXECUTE privilege to call a procedure. By default it runs with its definer's rights (SQL SECURITY DEFINER), so you can let an app account call transfer without giving it direct UPDATE rights on accounts.
Pros and cons#
Many teams keep business logic in the application and use procedures for data-heavy batch jobs and permission boundaries. Choose deliberately and be consistent.
What's next#
Procedures are called. Next you'll write stored functions, which you can use inside SQL expressions just like built-in functions.
Check your understanding
Quick quiz
1.Why do we change the DELIMITER before CREATE PROCEDURE in the mysql client?
2.How do you call a procedure with an OUT parameter and read the result?
3.What does
DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END;do?
Finished reading?
Mark this lesson complete to track your progress.