DevLearningTools

LEARN · SQL

SQL Stored Procedures

A stored procedure is a named, reusable routine saved in the database itself. Learn the concept and each database's real syntax, including the one with no support at all.

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.

MySQL / MariaDB
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.

SQL Server
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.

PostgreSQL
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);
Oracle (PL/SQL)
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

DatabaseStored Procedure Support
MySQL / MariaDB / PostgreSQL / SQL Server / OracleSupported (syntax varies significantly)
SQLiteNot supported at all
NOTE

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.

Answer — MySQL / MariaDB
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.

SQLite / PostgreSQL

Fast, no server, no ads.

Open DB Fiddle ↗

MySQL / SQL Server

Switch databases with one dropdown.

Open SQL Fiddle ↗

Both open a third-party SQL playground in a new tab. External site terms and privacy policy apply.