DEV Community

Yuri Peixinho
Yuri Peixinho

Posted on

SQL: Stored Procedures e Functions

Introdução

Quando você manda uma query SQL avulsa, o banco faz isso toda vez:

  1. Parse — analisa a sintaxe.
  2. Otimização — decide o melhor plano de execução (quais índices usar, ordem dos JOINs, etc.).
  3. Execução — roda de fato.

Uma stored procedure/function é salva no banco com nome próprio, e o banco guarda (ou reutiliza) o plano de execução já otimizado para as próximas chamadas. Isso poupa o trabalho de reanalisar e replanejar a mesma lógica repetidamente — é isso que "precompilado" quer dizer na prática (não é bytecode compilado feito um .exe, é o plano de execução em cache).

Stored Procedures

Um bloco de código SQL + lógica procedural (variáveis, IFWHILE, loops) salvo no banco, que você executa/chama — não usa dentro de um SELECT.

Sintaxe (varia bastante entre bancos)

SQL Server (T-SQL):

CREATE PROCEDURE TransferirSaldo
  @conta_origem INT,
  @conta_destino INT,
  @valor DECIMAL(10,2)
AS
BEGIN
  UPDATE contas SET saldo = saldo - @valor WHERE id = @conta_origem;
  UPDATE contas SET saldo = saldo + @valor WHERE id = @conta_destino;
END;

-- Chamando:
EXEC TransferirSaldo @conta_origem= 1, @conta_destino= 2, @valor= 100;
Enter fullscreen mode Exit fullscreen mode

Repare que já conectamos com assunto de Transact e ACID: a procedure encapsula a transação inteira (os dois UPDATEs) — isso é extremamente comum na prática. A lógica de negócio "transferência bancária" mora em um único lugar, versionada e reutilizável.

Parâmetros: IN, OUT e INOUT

IN (padrão) Recebe um valor de fora para dentro da procedure
OUT Devolve um valor calculado de dentro para fora, para a variável do chamador
INOUT Funciona nos dois sentidos — entra com um valor, sai modificado

Lógica procedural: variáveis, IF, loops

Isso é o que diferencia uma procedure de um SELECT comum. Ela pode ter controle de fluxo, como uma linguagem de programação de verdade:

CREATE PROCEDURE processar_pedidos_pendentes()
LANGUAGE plpgsql
AS $$
DECLARE
  pedido RECORD;
  contadorINT := 0;
BEGIN
  FOR pedidoIN SELECT * FROM pedidos WHERE status = 'pendente' LOOP
    IF pedido.total > 1000 THEN
      UPDATE pedidos SET status = 'em_analise' WHERE id = pedido.id;
    ELSE
      UPDATE pedidos SET status = 'aprovado' WHERE id = pedido.id;
    END IF;
    contador := contador+ 1;
  END LOOP;

  RAISE NOTICE'% pedidos processados', contador;
END;
$$;
Enter fullscreen mode Exit fullscreen mode

Isso é impossível de fazer em um SELECT puro. É por isso que procedures existem: para lógica que precisa de passos sequenciais, decisões e repetição, não só "buscar dados".

Functions

Um bloco de código salvo no banco que obrigatoriamente retorna um valor, e pode ser usado dentro de outras queries — em SELECT, WHERE, ORDER BY — exatamente como ROUND() ou UPPER() (que são, na verdade, funções nativas do banco; as suas são "customizadas").

Sintaxe

CREATE FUNCTION CalcularIdade(@data_nascimento DATE)
RETURNS INT
AS
BEGIN
  RETURN DATEDIFF(YEAR, @data_nascimento, GETDATE());
END;

SELECT nome, dbo.CalcularIdade(data_nascimento) AS idade FROM clientes;
Enter fullscreen mode Exit fullscreen mode

Scalar Function vs. Table-Valued Function

Tipo Retorna Exemplo de uso
Scalar Um único valor (número, texto, data) calcular_idade() acima — um INT por linha
Table-valued Uma tabela inteira (linhas e colunas) Uma função que retorna "todos os pedidos de um cliente"
-- Table-valued function (PostgreSQL):
CREATE FUNCTION pedidos_do_cliente(cliente_id INT)
RETURNS TABLE(pedido_id INT, total NUMERIC, data DATE)
LANGUAGE plpgsql
AS $$
BEGIN
  RETURN QUERY
    SELECT id, total, data_pedido FROM pedidos WHERE cliente_id = $1;
END;
$$;

-- Usando como se fosse uma tabela:
SELECT * FROM pedidos_do_cliente(1) WHERE total > 100;
Enter fullscreen mode Exit fullscreen mode

Isso conecta diretamente com view. Uma table-valued function é como uma "view com parâmetros". A view não aceita argumentos; a function sim.

Diferenças cruciais: Procedure vs. Function

Stored Procedure Function
Retorno Opcional (pode não retornar nada, ou retornar via OUT) Obrigatório — sempre retorna um valor
Uso em SELECT ❌ Não pode ser usada dentro de um SELECT/WHERE ✅ Pode ser usada como se fosse uma coluna/expressão
Como se chama CALL procedure(...) / EXEC procedure Dentro de uma query: SELECT function(...)
Transações ✅ Pode conter COMMIT/ROLLBACK dentro dela ❌ Geralmente não pode controlar transação (roda dentro da transação de quem chamou)
Parâmetros de saída Suporta OUT/INOUT Só retorno via RETURN (sem OUT na maioria dos bancos)
Efeitos colaterais (side effects) Esperado — fazer INSERT/UPDATE/DELETE é o uso típico Deveria ser evitado — functions idealmente são "puras" (calculam e retornam, sem alterar dados), embora tecnicamente algumas linguagens permitam
Uso típico Automatizar processos, lotes, transações complexas Cálculos reutilizáveis, regras de negócio usadas em queries

Regra prática para decidir qual usar: se você precisa buscar/calcular e devolver um valor para usar dentro de uma query, use function. Se você precisa executar uma sequência de ações (múltiplos UPDATEs, lógica de transação, processamento em lote), use procedure.

Top comments (0)