Stored Procedures
Save a parameterised SQL program in the database, run it with EXEC, and add IF/ELSE logic and TRY…CATCH error handling.
Every morning the analyst types the same "top batters above X runs" query, changing only the number. A stored procedure saves that query (and any logic around it) in the database under a name, so anyone can run it with one line and a parameter.
Definition
A stored procedure is a named, saved program of one or more SQL statements, stored in the database and executed on demand with
EXEC. It can accept input parameters, return result sets or output values, and contain procedural logic such as variables,IF … ELSE, loops andTRY … CATCHerror handling.
- Named and saved — created once with
CREATE PROCEDURE, it stays in the database until dropped. - Executed on demand — nothing happens until someone runs
EXEC procedure_name(unlike a trigger). - Parameters — values like
@MinRunsmake one procedure reusable for many situations. - Procedural logic — T-SQL adds programming features that a plain
SELECTdoesn't have.
Note: Stored procedures are a SQL Server (T-SQL) feature here. SQLite (the playground) has no stored procedures, so these examples are shown as code to run in SSMS. MySQL and PostgreSQL have them too, with different syntax.
Syntax
sql
CREATE PROCEDURE procedure_name
@param1 DATA_TYPE,
@param2 DATA_TYPE = default_value -- optional parameter
AS
BEGIN
SET NOCOUNT ON; -- hide "n rows affected" messages
-- SQL statements using @param1, @param2
END;
EXEC procedure_name @param1 = value1, @param2 = value2;
ALTER PROCEDURE procedure_name ...; -- change it
DROP PROCEDURE procedure_name; -- remove it| Part | Meaning |
|---|---|
CREATE PROCEDURE (or PROC) | saves a new procedure |
@MinRuns INT | an input parameter — variables in T-SQL start with @ |
= 500 | default value, makes the parameter optional |
AS BEGIN … END | the body: the statements that run |
EXEC (or EXECUTE) | runs the procedure |
Example — GetTopBatters with a parameter
sql
CREATE PROCEDURE GetTopBatters
@MinRuns INT
AS
BEGIN
SELECT name, runs
FROM players
WHERE runs >= @MinRuns
ORDER BY runs DESC;
END;
EXEC GetTopBatters @MinRuns = 700;| name | runs |
|---|---|
| Jos Buttler | 850 |
| Virat Kohli | 750 |
| David Warner | 700 |
Run it again with @MinRuns = 500 and you get 4 players — same procedure, different input. Parameters make it flexible.
Stored procedure vs plain query vs Python
| Plain query | Stored procedure | Python script | |
|---|---|---|---|
| Stored in database? | No (typed each time) | Yes | No (separate file) |
| Parameters | Edit the text | Yes (@MinRuns) | Yes |
| Logic (IF, loops, errors) | Very limited | Yes (T-SQL) | Yes (any logic) |
| Speed with data | Fast | Fast — runs next to the data | Slower — data moves out |
| Best for | One-off questions | Repeated database jobs | Complex apps / ML |
Other benefits: security (users can be allowed to EXEC a procedure without direct access to the tables), less network traffic (one EXEC line instead of many statements), and plan reuse (SQL Server caches the execution plan).
Flow control — IF / ELSE and variables
sql
CREATE PROCEDURE AddRuns
@PlayerId INT,
@Runs INT = NULL
AS
BEGIN
IF @Runs IS NULL
SET @Runs = 0; -- no value given? use 0
IF @Runs < 0
BEGIN
PRINT 'Runs cannot be negative';
RETURN; -- stop the procedure
END
ELSE
BEGIN
UPDATE players
SET runs = runs + @Runs
WHERE id = @PlayerId;
END
END;
EXEC AddRuns @PlayerId = 4, @Runs = 50; -- Dhoni 350 -> 400IF … ELSE decides which step runs. DECLARE @var creates a local variable, SET assigns it, and BEGIN … END groups several statements under one IF.
Error handling — TRY … CATCH
sql
CREATE PROCEDURE SafeUpdate
AS
BEGIN
BEGIN TRY
UPDATE players
SET runs = runs / 0; -- may fail
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS error_no, -- 8134
ERROR_MESSAGE() AS problem; -- 'Divide by zero error encountered.'
END CATCH
END;| Step | What happens |
|---|---|
BEGIN TRY | SQL Server attempts the statements |
| No error | END TRY → done, the CATCH block is skipped |
| Error | control jumps to BEGIN CATCH — the procedure does not crash |
| In CATCH | ERROR_MESSAGE(), ERROR_NUMBER(), ERROR_LINE() describe the problem; often you ROLLBACK a transaction or log the error |
Common mistakes
- ❌ Forgetting
@on parameters (MinRuns INT). ✅@MinRuns INT. - ❌
EXEC GetTopBatterswith no value when the parameter has no default → error "expects parameter '@MinRuns'". ✅ pass it, or give it a default. - ❌ Running
CREATE PROCEDUREtwice → "already an object named…". ✅ALTER PROCEDUREorCREATE OR ALTER PROCEDURE(2016 SP1+). - ❌ Building SQL by gluing user text into a string → SQL injection. ✅ use parameters.
- ❌ Naming your procedures
sp_…→ SQL Server first searches themasterdatabase forsp_names. ✅ useusp_or no prefix.
SQL Server vs MySQL / PostgreSQL
| SQL Server | MySQL | PostgreSQL | |
|---|---|---|---|
| Create | CREATE PROCEDURE p @x INT AS BEGIN … END | CREATE PROCEDURE p(IN x INT) BEGIN … END | CREATE PROCEDURE p(x INT) LANGUAGE plpgsql AS $$ … $$ |
| Run | EXEC p @x = 1 | CALL p(1) | CALL p(1) |
Interview tip
Q: Stored procedure vs function?
A procedure is run with EXEC, can change data (INSERT/UPDATE/DELETE), can return several result sets and use TRY…CATCH. A user-defined function is used inside a query (SELECT dbo.fn(x)), must return a value or a table, and cannot modify table data.
Key points to remember
- A stored procedure is a named SQL program saved in the database and run on demand with EXEC.
- Input parameters start with @ (e.g. @MinRuns INT) and can have default values.
- The body goes between AS BEGIN … END; change it with ALTER PROCEDURE, remove it with DROP PROCEDURE.
- T-SQL adds procedural logic: DECLARE / SET variables, IF … ELSE, loops and RETURN.
- BEGIN TRY … END TRY BEGIN CATCH … END CATCH handles errors; ERROR_MESSAGE() describes the problem.
- Procedures run next to the data, reduce network traffic, reuse cached plans and allow EXEC-only security.
- Stored procedures are not available in SQLite (the playground) — use SSMS / SQL Server to run them.
Try it yourself
GetTopBatters with a parameter (SQL Server)
CREATE PROCEDURE GetTopBatters
@MinRuns INT = 500 -- default if no value is passed
AS
BEGIN
SET NOCOUNT ON;
SELECT name, runs
FROM players
WHERE runs >= @MinRuns
ORDER BY runs DESC;
END;
GO
EXEC GetTopBatters @MinRuns = 700; -- Buttler 850, Kohli 750, Warner 700
EXEC GetTopBatters; -- uses the default 500 -> 4 playersSQL Server-specific — run this in SQL Server (SSMS / Azure Data Studio).
Try it: the query the procedure runs
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
IF / ELSE and TRY … CATCH (SQL Server)
CREATE PROCEDURE AddRuns
@PlayerId INT,
@Runs INT = NULL
AS
BEGIN
SET NOCOUNT ON;
IF @Runs IS NULL
SET @Runs = 0;
BEGIN TRY
IF @Runs < 0
THROW 50001, 'Runs cannot be negative.', 1;
UPDATE players
SET runs = runs + @Runs
WHERE id = @PlayerId;
SELECT name, runs FROM players WHERE id = @PlayerId;
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS error_no,
ERROR_MESSAGE() AS problem;
END CATCH
END;
GO
EXEC AddRuns @PlayerId = 4, @Runs = 50; -- MS Dhoni 400
EXEC AddRuns @PlayerId = 4, @Runs = -10; -- 50001 | Runs cannot be negative.SQL Server-specific — run this in SQL Server (SSMS / Azure Data Studio).
Practice: the query behind a 'players by country' procedure
Runs on a fresh IPL practice database in your browser · edit the query and press Ctrl + Enter
Revision Flashcards
Tap a card to flip it and see the answer.
