Every statement so far has been written out fresh each time it runs. A stored procedure is a named routine, one or more SQL statements, optionally with parameters, saved inside the database itself and called by name, instead of resending the whole statement every time.
Learning Objectives
- Explain what a stored procedure is and why it's reusable in a way a plain query isn't.
- Write a simple stored procedure with a parameter on at least one database.
- Know which database in this course has no stored procedure support at all.
MySQL / MariaDB
DELIMITER // temporarily changes the statement terminator from ; to //, needed because the procedure's own body contains semicolons that shouldn't end the CREATE PROCEDURE statement itself. CALL give_raise(1, 5.0) runs it, giving department 1 (Engineering) a 5% raise.
DELIMITER // CREATE PROCEDURE give_raise(IN dept_id INT, IN raise_pct DECIMAL(5,2)) BEGIN UPDATE employees SET salary = salary * (1 + raise_pct / 100) WHERE department_id = dept_id; END // DELIMITER ; CALL give_raise(1, 5.0);
SQL Server
Parameters are prefixed with @ throughout, and no DELIMITER trick is needed, SQL Server's batch separator (GO) works differently. EXEC (or EXECUTE) runs the procedure.
CREATE PROCEDURE give_raise @dept_id INT, @raise_pct DECIMAL(5,2) AS BEGIN UPDATE employees SET salary = salary * (1 + @raise_pct / 100) WHERE department_id = @dept_id; END; EXEC give_raise @dept_id = 1, @raise_pct = 5.0;
PostgreSQL and Oracle
PostgreSQL (version 11+) needs LANGUAGE plpgsql and the $$ ... $$ body delimiters. Oracle's PL/SQL wraps the body in IS ... BEGIN ... END, and CREATE OR REPLACE lets the same statement update an existing procedure without a separate DROP first.
CREATE PROCEDURE give_raise(dept_id INT, raise_pct NUMERIC) LANGUAGE plpgsql AS $$ BEGIN UPDATE employees SET salary = salary * (1 + raise_pct / 100) WHERE department_id = dept_id; END; $$; CALL give_raise(1, 5.0);
CREATE OR REPLACE PROCEDURE give_raise( dept_id IN NUMBER, raise_pct IN NUMBER ) IS BEGIN UPDATE employees SET salary = salary * (1 + raise_pct / 100) WHERE department_id = dept_id; END; / EXEC give_raise(1, 5.0);
SQLite Has No Stored Procedures
| Database | Stored Procedure Support |
|---|---|
| MySQL / MariaDB / PostgreSQL / SQL Server / Oracle | Supported (syntax varies significantly) |
| SQLite | Not supported at all |
SQLite is deliberately a lightweight, embedded, file-based database, it has no server process to store and run procedures inside. Any logic that would be a stored procedure elsewhere has to live in the application code instead when targeting SQLite.
Try It Yourself
On MySQL, write a stored procedure that deletes any employee by id, then call it for employee id 99.
DELIMITER // CREATE PROCEDURE remove_employee(IN emp_id INT) BEGIN DELETE FROM employees WHERE id = emp_id; END // DELIMITER ; CALL remove_employee(99);
Frequently Asked Questions
What's the difference between a stored procedure and a stored function?
A procedure performs an action and is called on its own (CALL / EXEC); it isn't required to return a value. A function must return a value and is used inside an expression, like SELECT my_function(column). The two serve different roles even though both live inside the database.
Why use a stored procedure instead of just sending the same SQL from the application every time?
Reuse (defined once, called by name from anywhere), reduced network traffic for multi-statement logic, and the ability to grant EXECUTE permission on a procedure without granting direct table access, letting an application run specific approved operations without broader database permissions.
Common Beginner Mistakes
Forgetting DELIMITER // on MySQL/MariaDB and hitting a syntax error
Without changing the delimiter first, MySQL ends the CREATE PROCEDURE statement at the body's first semicolon, before BEGIN...END is even complete, producing a confusing error. DELIMITER // (and switching back with DELIMITER ; afterward) is required.
Assuming stored procedure syntax is portable across databases
It's one of the least portable areas in all of SQL, parameter syntax, body delimiters, and even the CREATE statement's keywords differ meaningfully between MySQL, SQL Server, PostgreSQL, and Oracle, and SQLite has no equivalent at all.
Best Practices
- Use clear, descriptive procedure names, the same naming-convention principle from Module 1 applies here too.
- Document each parameter's expected meaning, since the signature alone often isn't self-explanatory.
- Don't assume SQLite support, plan application-level logic instead when SQLite is a target.
Interview Questions
What is a stored procedure, and why would a team use one?
A stored procedure is a named, reusable routine of one or more SQL statements saved inside the database, callable by name instead of resending the full statement each time. It supports reuse, reduces round-trips for multi-statement logic, and allows granting execute permission on a specific approved operation without granting broader table access.
Which database in this course has no stored procedure support, and what does that mean in practice?
SQLite, it's a lightweight, embedded, file-based database with no server process to host procedures. Any logic that would otherwise be a stored procedure needs to live in the calling application's code when the target is SQLite.
Summary
A stored procedure is a named, reusable routine saved in the database and called by name, with syntax that differs substantially across MySQL/MariaDB, SQL Server, PostgreSQL, and Oracle, and no support at all on SQLite.
What's Next?
SQL Comments next, a short lesson on documenting a query, single-line and block comments, portable everywhere.
Ready to Practice SQL?
Write and run real SQL queries online, right in your browser, no install or signup required. Pick a playground based on which database you want to practice on.
Both open a third-party SQL playground in a new tab. External site terms and privacy policy apply.