Stored Procedures
A stored procedure is a named, reusable block of SQL saved in the database. It accepts parameters, executes multiple statements, and can include conditional logic and loops.
-- MySQL stored procedure:
DELIMITER //
CREATE PROCEDURE GetLearnersByCity(
IN p_city VARCHAR(50),
OUT p_count INT
)
BEGIN
-- Return learner records:
SELECT learner_id, full_name, course, mark
FROM learners
WHERE city = p_city
ORDER BY mark DESC;
-- Set the output parameter:
SELECT COUNT(*)
INTO p_count
FROM learners
WHERE city = p_city;
END //
DELIMITER ;
-- Call the procedure:
CALL GetLearnersByCity('Johannesburg', @learner_count);
SELECT @learner_count AS johannesburg_learner_count;
-- Procedure with conditional logic:
DELIMITER //
CREATE PROCEDURE UpdateLearnerMark(
IN p_learner_id INT,
IN p_new_mark DECIMAL(5, 2)
)
BEGIN
DECLARE v_current_mark DECIMAL(5, 2);
-- Validate mark range:
IF p_new_mark < 0 OR p_new_mark > 100 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Mark must be between 0 and 100';
END IF;
-- Get current mark:
SELECT mark INTO v_current_mark
FROM learners WHERE learner_id = p_learner_id;
IF v_current_mark IS NULL THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Learner not found';
END IF;
-- Update:
UPDATE learners
SET mark = p_new_mark
WHERE learner_id = p_learner_id;
SELECT CONCAT('Mark updated from ', v_current_mark, ' to ', p_new_mark) AS message;
END //
DELIMITER ;
CALL UpdateLearnerMark(1, 82.0);
-- DROP and LIST procedures:
DROP PROCEDURE IF EXISTS GetLearnersByCity;
SHOW PROCEDURE STATUS WHERE Db = 'fmtali'; -- MySQL
-- PostgreSQL equivalent (functions, not procedures):
CREATE OR REPLACE FUNCTION get_learners_by_city(p_city TEXT)
RETURNS TABLE(learner_id INT, full_name TEXT, mark DECIMAL) AS $$
BEGIN
RETURN QUERY
SELECT l.learner_id, l.full_name, l.mark
FROM learners l
WHERE l.city = p_city;
END;
$$ LANGUAGE plpgsql;
SELECT * FROM get_learners_by_city('Cape Town');
Practice Task
Your Turn
Write stored procedures: (1) EnrolLearner(name, course) — inserts a learner and returns the new ID; (2) GetCourseStats(course) — returns count, average, min, max for a course; (3) MarkAttendance(learner_id, date, status) — inserts an attendance record after validating the status is one of Present/Absent/Late. Test all three with CALL.
Common Mistakes
- DELIMITER change in MySQL — without it, the semicolons inside the procedure end the procedure definition early.
- Forgetting DECLARE before using a variable.
- Stored procedures are database-specific — MySQL syntax differs from PostgreSQL (functions) and SQL Server (T-SQL).
- Business logic in stored procedures — harder to test, debug, and version control than application-layer code.
Professional Tip
Stored procedures are best used for complex multi-statement operations that benefit from running close to the data (bulk processing, complex reporting). For simple CRUD, keep logic in your application code where it is easier to test and version.
Mini Quiz
What is a stored procedure?