MySQL: Uma explicação detalhada sobre procedimentos…

Última atualização: 2026-08-26

Os procedimentos armazenados são conjuntos pré-compilados de instruções SQL — basta escrevê-los uma vez para chamá-los várias vezes.

Esta aula aborda a criação e o uso de procedimentos armazenados e funções.

100%
graph TB
    A[CALL Stored Procedures] --> B[Parameter Passing IN/OUT/INOUT]
    B --> C[DECLARE Declare a variable]
    C --> D{Process Control}
    D --> E[IF / CASE Conditions]
    D --> F[WHILE / LOOP Loop]
    D --> G[Cursor CURSOR Iterate]
    E --> H[ExecuteSQL]
    F --> H
    G --> H
    H --> I[OUTParameter Return]
    I --> J[End]

1. O que você vai aprender


2. Cenários da vida real

(1) Desafio: Escrever repetidamente lógicas complexas

Calculamos a folha de pagamento total de cada departamento todos os meses, mas a consulta SQL é muito longa e é executada repetidamente.

(2) Solução utilizando procedimentos armazenados

SQL
CREATE PROCEDURE sp_dept_salary_stats()
BEGIN
    SELECT department, SUM(salary) AS total_salary, AVG(salary) AS avg_salary
    FROM employees
    GROUP BY department;
END;

-- Call
CALL sp_dept_salary_stats();

3. Criação de um procedimento armazenado

▶ Exemplo: Procedimento armazenado básico

SQL
-- Create a Stored Procedure
DELIMITER //
CREATE PROCEDURE sp_get_user(IN user_id INT)
BEGIN
    SELECT * FROM users WHERE id = user_id;
END //
DELIMITER ;

-- Call
CALL sp_get_user(1);
▶ Experimente

▶ Exemplo: Com um parâmetro OUT

SQL
DELIMITER //
CREATE PROCEDURE sp_count_users(OUT total INT)
BEGIN
    SELECT COUNT(*) INTO total FROM users;
END //
DELIMITER ;

-- Call
CALL sp_count_users(@total);
SELECT @total;
▶ Experimente

▶ Exemplo: Com parâmetros INOUT

SQL
DELIMITER //
CREATE PROCEDURE sp_double(INOUT num INT)
BEGIN
    SET num = num * 2;
END //
DELIMITER ;

-- Call
SET @num = 5;
CALL sp_double(@num);
SELECT @num;  -- 10
▶ Experimente

4. Declaração de variáveis

▶ Exemplo: DECLARE variável

SQL
DELIMITER //
CREATE PROCEDURE sp_variable_demo()
BEGIN
    DECLARE total INT DEFAULT 0;
    DECLARE avg_salary DECIMAL(10,2);
    DECLARE user_name VARCHAR(50);
    
    -- Assignment
    SELECT COUNT(*) INTO total FROM employees;
    SELECT AVG(salary) INTO avg_salary FROM employees;
    
    -- Using Variables
    SELECT total, avg_salary;
END //
DELIMITER ;
▶ Experimente

5. Controle de processos

▶ Exemplo: Instrução IF

SQL
DELIMITER //
CREATE PROCEDURE sp_check_salary(IN emp_id INT)
BEGIN
    DECLARE emp_salary DECIMAL(10,2);
    
    SELECT salary INTO emp_salary FROM employees WHERE id = emp_id;
    
    IF emp_salary > 10000 THEN
        SELECT 'High salary' AS level;
    ELSEIF emp_salary > 5000 THEN
        SELECT 'Medium salary' AS level;
    ELSE
        SELECT 'Low salary' AS level;
    END IF;
END //
DELIMITER ;
▶ Experimente

▶ Exemplo: Instrução CASE

SQL
DELIMITER //
CREATE PROCEDURE sp_order_status(IN order_id INT)
BEGIN
    DECLARE order_status VARCHAR(20);
    
    SELECT status INTO order_status FROM orders WHERE id = order_id;
    
    CASE order_status
        WHEN 'pending' THEN SELECT 'Order is pending' AS message;
        WHEN 'paid' THEN SELECT 'Order is paid' AS message;
        WHEN 'shipped' THEN SELECT 'Order is shipped' AS message;
        ELSE SELECT 'Unknown status' AS message;
    END CASE;
END //
DELIMITER ;
▶ Experimente

▶ Exemplo: Laço WHILE

SQL
DELIMITER //
CREATE PROCEDURE sp_sum_1_to_n(IN n INT, OUT total INT)
BEGIN
    DECLARE i INT DEFAULT 1;
    SET total = 0;
    
    WHILE i <= n DO
        SET total = total + i;
        SET i = i + 1;
    END WHILE;
END //
DELIMITER ;

-- Call
CALL sp_sum_1_to_n(100, @total);
SELECT @total;  -- 5050
▶ Experimente

6. Cursor

▶ Exemplo: Iteração do cursor

SQL
DELIMITER //
CREATE PROCEDURE sp_list_users()
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE user_name VARCHAR(50);
    DECLARE user_email VARCHAR(100);
    
    -- Declare cursor
    DECLARE cur_users CURSOR FOR 
        SELECT username, email FROM users;
    
    -- End of cursor handler
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    
    -- Open cursor
    OPEN cur_users;
    
    -- Iterate
    read_loop: LOOP
        FETCH cur_users INTO user_name, user_email;
        IF done THEN
            LEAVE read_loop;
        END IF;
        SELECT user_name, user_email;
    END LOOP;
    
    -- Close cursor
    CLOSE cur_users;
END //
DELIMITER ;
▶ Experimente

7. Funções armazenadas

▶ Exemplo: Criando uma função

SQL
DELIMITER //
CREATE FUNCTION fn_calc_bonus(salary DECIMAL(10,2))
RETURNS DECIMAL(10,2)
DETERMINISTIC
BEGIN
    DECLARE bonus DECIMAL(10,2);
    
    IF salary > 10000 THEN
        SET bonus = salary * 0.2;
    ELSEIF salary > 5000 THEN
        SET bonus = salary * 0.1;
    ELSE
        SET bonus = salary * 0.05;
    END IF;
    
    RETURN bonus;
END //
DELIMITER ;

-- Using Functions
SELECT name, salary, fn_calc_bonus(salary) AS bonus FROM employees;
▶ Experimente

8. Gerenciamento de procedimentos armazenados

▶ Exemplo: Visualização e exclusão

SQL
-- View All Stored Procedures
SHOW PROCEDURE STATUS WHERE Db = 'mydb';

-- View the CREATE statement
SHOW CREATE PROCEDURE sp_get_user;

-- Delete a Stored Procedure
DROP PROCEDURE IF EXISTS sp_get_user;

-- Delete Function
DROP FUNCTION IF EXISTS fn_calc_bonus;
▶ Experimente

❓ Perguntas Frequentes

P: Qual é a diferença entre um procedimento armazenado e uma função? R: Um procedimento armazenado é chamado por meio da instrução CALL e não retorna um valor; uma função é chamada por meio da instrução SELECT e deve retornar um valor.

P: O que é DELIMITER? R: É o delimitador de instrução. Como o procedimento armazenado contém ;, ele precisa ser substituído por // para evitar que a instrução termine prematuramente.

P: Os procedimentos armazenados podem melhorar o desempenho? R: Os procedimentos armazenados são pré-compilados, o que reduz o tráfego de rede. No entanto, o otimizador moderno do MySQL já é bastante bom, portanto, o ganho de desempenho é limitado.

P: Qual é a diferença entre um procedimento armazenado e uma função? R: Um procedimento é chamado por meio da instrução CALL e pode ter parâmetros OUT sem retornar um valor, enquanto uma função usada em uma instrução SELECT deve RETURNAR um valor.

P: Os procedimentos armazenados podem ser vulneráveis à injeção de SQL? R: O uso de PREPARE combinado com CONCAT para construir instruções SQL pode levar à injeção; passar parâmetros diretamente é seguro.


📖 Resumo


📝 Exercícios

  1. Questão básica (Dificuldade: ⭐): Crie um procedimento armazenado que receba um ID de usuário como entrada e retorne as informações do usuário.

  2. Problema avançado (Dificuldade ⭐⭐): Crie um procedimento armazenado com uma instrução IF que retorne uma nota com base na pontuação.

  3. Problema de desafio (Dificuldade: ⭐⭐⭐): Use um cursor para percorrer a tabela de usuários, calcular e atualizar os pontos de cada usuário.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%