Alguns níveis atrás a gente já falou sobre procedimentos e funções no PostgreSQL. Agora chegou a hora de mergulhar mais fundo nisso.
Funções e procedimentos podem funcionar de boa sozinhos, mas na real, o sucesso do sistema geralmente depende de como eles interagem. O mais massa é que funções podem chamar outras funções, passando dados e até pegando o resultado de volta.
Funções vs Procedimentos: qual a diferença?
Bora relembrar rapidinho qual é a diferença entre funções e procedimentos no PostgreSQL:
Funções (
FUNCTION):- Retornam valores.
- Dá pra usar elas no
SELECT. - Normalmente são usadas pra calcular ou transformar dados.
Procedimentos (
PROCEDURE):- Não retornam valores direto.
- São usadas pra fazer operações tipo inserir, atualizar ou deletar dados.
- Você chama elas usando o comando
CALL.
Passando dados entre funções
Indo pra prática, vamos começar com um exemplo básico de como passar dados entre uma função e um procedimento. Basicamente, a troca de dados entre funções rola pelos parâmetros e pelos valores retornados.
Olha só como fica chamar uma função dentro de outra função:
CREATE OR REPLACE FUNCTION get_student_name(student_id INT)
RETURNS TEXT AS $$
DECLARE
student_name TEXT;
BEGIN
-- Pegando o nome do estudante pelo ID dele
SELECT name INTO student_name FROM students WHERE id = student_id;
-- Retornando o nome
RETURN student_name;
END;
$$ LANGUAGE plpgsql;
Dá pra chamar essa função de dentro de outra função:
CREATE OR REPLACE FUNCTION welcome_student(student_id INT)
RETURNS TEXT AS $$
DECLARE
message TEXT;
BEGIN
-- Pegando o nome do estudante usando outra função
message := 'Bem-vindo, ' || get_student_name(student_id) || '!';
-- Retornando a mensagem de boas-vindas
RETURN message;
END;
$$ LANGUAGE plpgsql;
- A função
get_student_nameretorna o nome do estudante pelo identificador dele (student_id). - Na outra função —
welcome_student— esse nome é usado pra montar a mensagem de boas-vindas.
Obs: Pegar dados usando SELECT INTO salva o resultado da query numa variável do PL/pgSQL.
Exemplo de chamada de procedimentos dentro de funções
Agora bora ver como chamar um procedimento de dentro de uma função. Imagina que a gente tem um procedimento que registra a hora que o estudante entrou no sistema:
CREATE OR REPLACE PROCEDURE log_student_entry(student_id INT)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO log_entries(student_id, entry_time)
VALUES (student_id, NOW());
END;
$$;
Agora vamos chamar esse procedimento de dentro de uma função, onde ele vai registrar a entrada e retornar uma mensagem:
CREATE OR REPLACE FUNCTION student_login(student_id INT)
RETURNS TEXT AS $$
BEGIN
-- Chamando o procedimento pra registrar o login
CALL log_student_entry(student_id);
-- Retornando a mensagem
RETURN 'Login do estudante registrado com sucesso.';
END;
$$ LANGUAGE plpgsql;
Exemplos práticos de interação
Exemplo 1: cálculo do valor total do pedido e log do pedido
Pensa que você tá mexendo num sistema de pedidos online. Pra calcular o valor total do pedido, você tem uma função:
CREATE OR REPLACE FUNCTION calculate_order_total(order_id INT)
RETURNS NUMERIC AS $$
DECLARE
total NUMERIC;
BEGIN
-- Somando todos os itens do pedido
SELECT SUM(price * quantity) INTO total
FROM order_items
WHERE order_id = order_id;
RETURN total;
END;
$$ LANGUAGE plpgsql;
Pra salvar o valor total do pedido, tem um procedimento:
CREATE OR REPLACE PROCEDURE log_order_total(order_id INT, total NUMERIC)
LANGUAGE plpgsql
AS $$
BEGIN
INSERT INTO order_totals(order_id, total)
VALUES (order_id, total);
END;
$$;
Agora vamos juntar tudo:
CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS TEXT AS $$
DECLARE
total NUMERIC;
BEGIN
-- Chamando a função pra calcular o total
total := calculate_order_total(order_id);
-- Registrando o total usando o procedimento
CALL log_order_total(order_id, total);
RETURN 'Pedido processado com sucesso.';
END;
$$ LANGUAGE plpgsql;
Exemplo 2: pegando a maior nota do estudante e atualizando o perfil
Função pra pegar a maior nota:
CREATE OR REPLACE FUNCTION get_highest_rating(student_id INT)
RETURNS INT AS $$
DECLARE
max_rating INT;
BEGIN
-- Pegando a maior nota do estudante
SELECT MAX(rating) INTO max_rating
FROM ratings
WHERE student_id = student_id;
RETURN max_rating;
END;
$$ LANGUAGE plpgsql;
Procedimento pra atualizar o perfil do estudante:
CREATE OR REPLACE PROCEDURE update_student_profile(student_id INT, max_rating INT)
LANGUAGE plpgsql
AS $$
BEGIN
UPDATE students
SET highest_rating = max_rating
WHERE id = student_id;
END;
$$;
Função pra chamar essas operações:
CREATE OR REPLACE FUNCTION refresh_student_profile(student_id INT)
RETURNS TEXT AS $$
DECLARE
max_rating INT;
BEGIN
-- Pegando a maior nota
max_rating := get_highest_rating(student_id);
-- Atualizando o perfil do estudante
CALL update_student_profile(student_id, max_rating);
RETURN 'Perfil atualizado com sucesso.';
END;
$$ LANGUAGE plpgsql;
Erros comuns na interação
Um dos erros mais comuns é quando os tipos de dados não batem entre a função e o procedimento. Por exemplo, se o procedimento espera um parâmetro do tipo NUMERIC, mas você manda um INTEGER, o PostgreSQL vai reclamar de incompatibilidade de tipos. Sempre confere se os tipos estão certinhos.
Outro erro é criar chamadas cíclicas, tipo a função A chama a função B, e a B chama a A de novo. Isso vira um loop infinito e derruba o sistema.
Por que isso é importante?
Pra que serve essa interação toda? No mundo real, funções e procedimentos são tipo "blocos de construção" de sistemas grandes. Eles deixam o código mais organizado, fácil de testar, de reaproveitar e de debugar. Por exemplo:
- Em entrevista de emprego, podem pedir pra você escrever uma função que chama um procedimento pra fazer uma operação mais complexa. Mostrar que você manja disso é um baita diferencial.
- Quando você tá desenvolvendo apps de verdade, tipo lojas virtuais, sistemas de log ou CRM, saber organizar a lógica usando funções e procedimentos deixa o código muito mais de boa de manter.
Se quiser se aprofundar mais em como funções e procedimentos interagem, dá uma olhada na documentação oficial do PL/pgSQL.
GO TO FULL VERSION