Creating a Stored Procedure
CREATE PROCEDURE <procedure_name> (parameter_list datatype)
BEGIN
<body -- SQL statements>
END;
Example:
DROP PROCEDURE IF EXISTS FetchTopEmployees;
CREATE PROCEDURE FetchTopEmployees()
BEGIN
SELECT emp_id, first_name, last_name FROM employee ORDER BY salary DESC LIMIT 20;
END;
CALL FetchTopEmployees();
Dropping a Procedure
DROP PROCEDURE procedure_name;
DROP PROCEDURE IF EXISTS procedure_name;
DROP PROCEDURE IF EXISTS FetchTopEmployees;
Invoking a Stored Procedure
CALL database_name.FetchTopEmployees();
Inspecting Stored Procedures
SHOW PROCEDURE STATUS;
SELECT name FROM mysql.proc WHERE db = 'company';
SELECT name FROM mysql.proc WHERE name LIKE '%bonus%';
Variable Declaration and Initialization
DECLARE variable_name [, variable_name] datatype [DEFAULT value]
DROP PROCEDURE IF EXISTS ComputeSample;
CREATE PROCEDURE ComputeSample()
BEGIN
DECLARE a INT;
DECLARE b INT DEFAULT 1;
SELECT a + b; -- yields NULL because a has no default
END;
CALL ComputeSample();
Assigning Variables with SET
SET var_name = value [, var_name = value] ...
CREATE PROCEDURE ComputeSample2()
BEGIN
DECLARE x INT;
DECLARE y INT DEFAULT 1;
SET x = 2, y = 3;
SELECT x + y;
END;
CALL ComputeSample2(); -- 5
Assigning Variables with SELECT ... INTO
SELECT <column | aggregate> INTO variable_name;
CREATE PROCEDURE ComputeSample3()
BEGIN
DECLARE cnt INT;
DECLARE bonus INT DEFAULT 10;
SELECT COUNT(1) INTO cnt FROM employee;
SELECT cnt + bonus;
END;
CALL ComputeSample3(); -- example count + 10
Conditional Branching with IF
IF search_condition THEN statement_list
[ELSEIF search_condition THEN statement_list] ...
[ELSE statement_list]
END IF;
DROP PROCEDURE IF EXISTS ClassifySalary;
CREATE PROCEDURE ClassifySalary(IN emp_id_param INT)
BEGIN
DECLARE grade VARCHAR(20);
DECLARE sal DECIMAL(10,2);
SELECT salary INTO sal FROM employee WHERE emp_id = emp_id_param LIMIT 1;
IF sal >= 100000 THEN
SET grade = 'Excellent';
ELSEIF sal >= 80000 THEN
SET grade = 'Good';
ELSEIF sal >= 50000 THEN
SET grade = 'Fair';
ELSE
SET grade = 'Poor';
END IF;
SELECT grade;
END;
CALL ClassifySalary(4);
Parameter Modes: IN, OUT, INOUT
IN– input parameter (default)OUT– return parameterINOUT– both input and output
IN Example
DROP PROCEDURE IF EXISTS ClassifySalaryIn;
CREATE PROCEDURE ClassifySalaryIn(IN sal_input DECIMAL(10,2))
BEGIN
DECLARE grade VARCHAR(20);
IF sal_input >= 100000 THEN
SET grade = 'Excellent';
ELSEIF sal_input >= 80000 THEN
SET grade = 'Good';
ELSEIF sal_input >= 50000 THEN
SET grade = 'Fair';
ELSE
SET grade = 'Poor';
END IF;
SELECT grade;
END;
CALL ClassifySalaryIn(85000);
OUT Example
DROP PROCEDURE IF EXISTS ClassifySalaryOut;
CREATE PROCEDURE ClassifySalaryOut(IN sal_input DECIMAL(10,2), OUT grade VARCHAR(20))
BEGIN
IF sal_input >= 100000 THEN
SET grade = 'Excellent';
ELSEIF sal_input >= 80000 THEN
SET grade = 'Good';
ELSEIF sal_input >= 50000 THEN
SET grade = 'Fair';
ELSE
SET grade = 'Poor';
END IF;
SELECT grade;
END;
CALL ClassifySalaryOut(0, @result);
SELECT @result;
INOUT Example
DROP PROCEDURE IF EXISTS TranslateGrade;
CREATE PROCEDURE TranslateGrade(INOUT grade_str VARCHAR(20))
BEGIN
IF grade_str = 'A' THEN
SET grade_str = 'Excellent';
ELSEIF grade_str = 'B' THEN
SET grade_str = 'Good';
ELSEIF grade_str = 'C' THEN
SET grade_str = 'Fair';
ELSE
SET grade_str = 'Poor';
END IF;
SELECT grade_str;
END;
SET @grade = 'A';
CALL TranslateGrade(@grade);
SELECT @grade;
System Variables
SELECT @@max_connections;
SET GLOBAL max_connections = 100;
CASE Expression
Two forms:
-- Form 1
CASE case_value
WHEN when_value THEN statement_list
[WHEN when_value THEN statement_list] ...
[ELSE statement_list]
END CASE;
-- Form 2
CASE
WHEN search_condition THEN statement_list
[WHEN search_condition THEN statement_list] ...
[ELSE statement_list]
END CASE;
Example using Form 2:
DROP PROCEDURE IF EXISTS RatePerformance;
CREATE PROCEDURE RatePerformance(IN score INT, OUT level VARCHAR(20))
BEGIN
CASE
WHEN score >= 90 THEN SET level = 'Outstanding';
WHEN score >= 75 THEN SET level = 'Proficient';
WHEN score >= 50 THEN SET level = 'Basic';
ELSE SET level = 'Needs Improvement';
END CASE;
END;
SET @lvl = '';
CALL RatePerformance(NULL, @lvl);
SELECT @lvl;
Loops
WHILE Loop
WHILE condition DO
statement_list
END WHILE;
DROP PROCEDURE IF EXISTS SumEvenNumbers;
CREATE PROCEDURE SumEvenNumbers(IN max_val INT)
BEGIN
DECLARE current_val INT DEFAULT 0;
DECLARE total INT DEFAULT 0;
WHILE current_val <= max_val DO
IF current_val % 2 = 0 THEN
SET total = total + current_val;
END IF;
SET current_val = current_val + 1;
END WHILE;
SELECT total;
END;
CALL SumEvenNumbers(10); -- 30
REPEAT ... UNTIL Loop
REPEAT
statement_list
UNTIL condition
END REPEAT;
DROP PROCEDURE IF EXISTS AccumulateDown;
CREATE PROCEDURE AccumulateDown(IN num INT)
BEGIN
DECLARE sum_total INT DEFAULT 0;
REPEAT
SET sum_total = sum_total + num;
SET num = num - 1;
UNTIL num = 0
END REPEAT;
SELECT sum_total;
END;
CALL AccumulateDown(10); -- 55
LOOP with LEAVE
[label:] LOOP
statement_list
END LOOP [label];
CREATE PROCEDURE AccumulateDownLoop(IN num INT)
BEGIN
DECLARE total INT DEFAULT 0;
accumulation: LOOP
SET total = total + num;
SET num = num - 1;
IF num <= 0 THEN
LEAVE accumulation;
END IF;
END LOOP accumulation;
SELECT total;
END;
CALL AccumulateDownLoop(10); -- 55
Cursors
DECLARE cursor_name CURSOR FOR select_statement;
OPEN cursor_name;
FETCH cursor_name INTO var_list;
CLOSE cursor_name;
-- DEALLOCATE PREPARE cursor_name; -- may not be supported in some versions
Example: give a 5% raise to all employee whose salary is below 60000.
DROP PROCEDURE IF EXISTS ApplyRaise;
CREATE PROCEDURE ApplyRaise()
BEGIN
DECLARE eid INT;
DECLARE cur_salary DECIMAL(10,2);
DECLARE done INT DEFAULT FALSE;
DECLARE emp_cursor CURSOR FOR SELECT emp_id, salary FROM employee;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
OPEN emp_cursor;
read_loop: LOOP
FETCH emp_cursor INTO eid, cur_salary;
IF done THEN
LEAVE read_loop;
END IF;
IF cur_salary < 60000 THEN
UPDATE employee SET salary = salary * 1.05 WHERE emp_id = eid;
END IF;
END LOOP;
CLOSE emp_cursor;
END;
CALL ApplyRaise();
Sample table structure used in examples:
CREATE TABLE employee (
emp_id INT PRIMARY KEY AUTO_INCREMENT,
first_name VARCHAR(50) NOT NULL,
last_name VARCHAR(50) NOT NULL,
salary DECIMAL(10,2),
hire_date DATE,
location VARCHAR(100)
);