Understanding MySQL Stored Procedures

Understanding MySQL Stored Procedures

Stored procedures in MySQL are powerful tools that allow developers to encapsulate multiple SQL statements into a single function, enhancing both efficiency and reusability. They simplify complex operations by reducing redundancy and making scripts easier to manage.
Cemil Tokatli
July 9, 2025
Topics:
Share:

Stored procedures in MySQL offer a structured way to handle complex logic directly within the database, providing a suite-like execution of commands that enhance efficiency and reduce client-server interactions. This article will guide you through the creation, execution, and benefits of using stored procedures in MySQL.

Setting Up Sample Tables

Before diving into stored procedures, let's establish a foundational dataset and table to work with. The following SQL statements create necessary tables and populate them with dummy data. We will use this example for all sections in the article.

CREATE TABLE employees (
    id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(100) NOT NULL,
    last_name VARCHAR(100) NOT NULL,
    email VARCHAR(100) NOT NULL,
    department VARCHAR(50) NOT NULL
);

INSERT INTO employees (first_name, last_name, email, department) VALUES
('John', 'Doe', 'johndoe@example.com', 'Sales'),
('Jane', 'Smith', 'janesmith@example.com', 'Marketing'),
('Alice', 'Johnson', 'alicejohnson@example.com', 'HR'),
('Robert', 'Brown', 'robertbrown@example.com', 'IT');

What are Stored Procedures?

Stored procedures are SQL code blocks stored and executed on the database server. They encapsulate a sequence of operations and can accept input parameters, process logic, and produce results. These procedures are similar to functions in traditional programming languages and offer several benefits. By centralizing business logic within the database, stored procedures promote data integrity and durability. They also possess the capability to perform complex calculations and data manipulations, making them versatile tools for developers. Furthermore, stored procedures can improve performance by reducing the number of round trips between a client and a server, as multiple operations can be executed with a single call. This can lead to more efficient resource usage and faster application response times.

  • Efficiency: Execute multiple SQL statements with a single call.
  • Reusability: Encapsulate logic that can be reused across applications.
  • Security: Control access and operations through centralized logic.
  • Reduced Traffic: Minimize data transfers by performing operations server-side.

Creating a Simple Stored Procedure

Let's create a stored procedure to retrieve employee details by department. This procedure demonstrates how to pass parameters and retrieve results.

DELIMITER //

CREATE PROCEDURE GetEmployeesByDepartment(IN dept VARCHAR(50))
BEGIN
    SELECT first_name, last_name, email FROM employees WHERE department = dept;
END //

DELIMITER ;
  • DELIMITER //: Redefines the statement delimiter to allow for multi-line code.
  • IN dept VARCHAR(50): An input parameter specifying the department name like a function argument.
  • SELECT ... FROM employees: The core query that filters employees by department. It is the actual function body that performs the given operation.

You can call this procedure with a simple command:

CALL GetEmployeesByDepartment('IT');

When you execute this procedure with a specified department, for example, 'IT', it outputs all employees within that department. For instance, calling CALL GetEmployeesByDepartment('IT'); would yield:

first_name last_name email
Robert Brown robertbrown@example.com

Modifying Data with Stored Procedures

Stored procedures aren't just for retrieving data; they can also modify it. Here's an example that updates employee email addresses based on their department:

DELIMITER //

CREATE PROCEDURE UpdateEmailDomain(IN new_domain VARCHAR(50), IN dept VARCHAR(50))
BEGIN
    UPDATE employees SET email = CONCAT(SUBSTRING_INDEX(email, '@', 1), '@', new_domain) 
    WHERE department = dept;
END //

DELIMITER ;
  • Modify email domains for all employees within a department.

Execute the procedure as follows:

CALL UpdateEmailDomain('newdomain.com', 'Sales');

Understanding IN-OUT Parameters

In MySQL stored procedures, parameters can be classified as IN, OUT, or INOUT. Understanding these parameter types is crucial for passing data in and retrieving results from procedures effectively.

IN Parameters

An IN parameter is used to pass a value into the procedure. The value of an IN parameter can be changed within the procedure, but the change does not affect the argument passed to the parameter from the calling statement.

OUT Parameters

An OUT parameter is used to return a value to the calling program. The procedure can change an OUT parameter and return a value to the calling program, providing a way to retrieve results.

INOUT Parameters

An INOUT parameter combines both IN and OUT functionality, meaning it can accept a value when the procedure is called and return a modified value afterward.

Here's an example demonstrating the usage of IN, OUT, and INOUT parameters:

DELIMITER //

CREATE PROCEDURE EmployeeCounter(IN dept VARCHAR(50), OUT emp_count INT, INOUT dept_name VARCHAR(50))
BEGIN
    SELECT COUNT(*) INTO emp_count FROM employees WHERE department = dept;
    SET dept_name = CONCAT('Department: ', dept_name);
END //

DELIMITER ;

This procedure takes a department name as input, returns the count of employees in that department, and modifies the department name string with additional text. You can execute the procedure as follows:

SET @count = 0;
SET @dept = 'IT';

CALL EmployeeCounter('IT', @count, @dept);

SELECT @count AS employee_count, @dept AS department_info;

After executing the above commands, the results can be displayed as:

employee_count department_info
1 Department: IT

Automating Data Checks with Loops in Stored Procedures

Stored procedures can automate repetitive tasks, like checking and updating data. Loops help in these operations. Here, we show how loops in a stored procedure can be used to find and mark repeat offenders in a library book loan system.

First, we have a simple dataset of book_loans to track if users frequently return books late.

CREATE TABLE book_loans (
    id INT PRIMARY KEY AUTO_INCREMENT,
    user_id INT,
    book_title VARCHAR(100),
    due_date DATE,
    return_date DATE,
    repeat_offender BOOLEAN DEFAULT FALSE
);

INSERT INTO book_loans (user_id, book_title, due_date, return_date) VALUES
(1, '1984', '2024-05-01', '2024-05-10'), -- overdue
(1, 'Brave New World', '2024-06-01', '2024-06-20'), -- overdue
(1, 'Fahrenheit 451', '2024-07-01', NULL), -- still overdue
(2, 'The Hobbit', '2024-06-15', '2024-06-14'), -- on time
(3, 'Dune', '2024-05-10', '2024-05-20'), -- overdue
(3, 'Dune Messiah', '2024-07-01', NULL); -- still overdue

The following stored procedure, FlagRepeatOverdueUsers, shows how loops identify users with multiple overdue books and update the database.

DELIMITER //

CREATE PROCEDURE FlagRepeatOverdueUsers()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE uid INT;
    DECLARE overdue_count INT;

    -- Cursor to loop through distinct users
    DECLARE user_cursor CURSOR FOR
        SELECT DISTINCT user_id FROM book_loans;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;

    OPEN user_cursor;

    user_loop: LOOP
        FETCH user_cursor INTO uid;
        IF done THEN
            LEAVE user_loop;
        END IF;

        -- Count overdue books for the user
        SELECT COUNT(*) INTO overdue_count
        FROM book_loans
        WHERE user_id = uid
          AND (
              (return_date IS NOT NULL AND return_date > due_date)
              OR (return_date IS NULL AND CURDATE() > due_date)
          );

        -- Update flag if the user has 2 or more overdue books
        IF overdue_count >= 2 THEN
            UPDATE book_loans
            SET repeat_offender = TRUE
            WHERE user_id = uid;
        ELSE
            UPDATE book_loans
            SET repeat_offender = FALSE
            WHERE user_id = uid;
        END IF;

    END LOOP;

    CLOSE user_cursor;
END //

DELIMITER ;

To execute this procedure, simply call:

CALL FlagRepeatOverdueUsers();

The FlagRepeatOverdueUsers procedure follows these steps:

  1. Cursor Initialization: A cursor named user_cursor is created to iterate over each distinct user in the book_loans table.
  2. User Loop: The procedure enters a loop where it fetches the user_id for each user into the variable uid.
  3. Overdue Count Calculation: For each user, it calculates the number of overdue books by counting records where the return_date is after due_date or the return_date is NULL and the current date is after the due_date.
  4. Repeat Offender Updating: If the overdue_count is 2 or more, the repeat_offender flag is set to TRUE for all loans by that user. Otherwise, it is set to FALSE.
  5. Loop End: The loop continues until all users have been processed.

The resulting book_loans table after the procedure execution would look like this:

id user_id book_title due_date return_date repeat_offender
1 1 1984 2024-05-01 2024-05-10 1
2 1 Brave New World 2024-06-01 2024-06-20 1
3 1 Fahrenheit 451 2024-07-01 NULL 1
4 2 The Hobbit 2024-06-15 2024-06-14 0
5 3 Dune 2024-05-10 2024-05-20 1
6 3 Dune Messiah 2024-07-01 NULL 1

Conclusion

MySQL stored procedures are powerful tools that streamline database interactions, reduce redundancy, and maintain data integrity. By encapsulating complex logic within the database, stored procedures empower developers to create efficient and reusable operations. As databases expand and application logic grows more complex, understanding stored procedures is a vital skill in optimizing database management and enhancing security.