PL/SQL - Guia Prático
Linguagem procedural do Oracle para desenvolvimento de lógica de negócio no banco de dados.
Fundamentos PL/SQL
Blocos PL/SQL, variáveis, tipos de dados e estrutura básica.
Blocos PL/SQL
Estrutura básica de um bloco PL/SQL (DECLARE, BEGIN, EXCEPTION, END)
Bloco Anônimo Básico
-- Bloco PL/SQL simples
DECLARE
v_nome VARCHAR2(100);
v_idade NUMBER := 30;
BEGIN
v_nome := 'João Silva';
DBMS_OUTPUT.PUT_LINE('Nome: ' || v_nome);
DBMS_OUTPUT.PUT_LINE('Idade: ' || v_idade);
END;
/ Bloco com Exception
DECLARE
v_salario NUMBER;
v_media NUMBER;
BEGIN
SELECT AVG(salario) INTO v_media
FROM funcionarios;
v_salario := 5000;
IF v_salario > v_media THEN
DBMS_OUTPUT.PUT_LINE('Acima da média');
ELSE
DBMS_OUTPUT.PUT_LINE('Abaixo da média');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Nenhum dado encontrado');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Erro: ' || SQLERRM);
END;
/ Variáveis e Tipos
Declaração de variáveis e tipos de dados em PL/SQL
Tipos Básicos
DECLARE
-- Tipos numéricos
v_id NUMBER := 1;
v_preco NUMBER(10,2) := 99.99;
v_quantidade INTEGER := 100;
-- Tipos de texto
v_nome VARCHAR2(100) := 'João';
v_descricao VARCHAR2(4000);
v_observacao CHAR(10) := 'ATIVO ';
-- Tipos de data
v_data DATE := SYSDATE;
v_timestamp TIMESTAMP := CURRENT_TIMESTAMP;
-- Boolean
v_ativo BOOLEAN := TRUE;
BEGIN
DBMS_OUTPUT.PUT_LINE('ID: ' || v_id);
DBMS_OUTPUT.PUT_LINE('Nome: ' || v_nome);
DBMS_OUTPUT.PUT_LINE('Data: ' || TO_CHAR(v_data, 'DD/MM/YYYY'));
END;
/ Ancoragem de Tipos
DECLARE
-- Ancorar tipo à coluna de uma tabela
v_nome_cliente clientes.nome%TYPE;
v_email_cliente clientes.email%TYPE;
-- Ancorar tipo a uma linha inteira
v_cliente clientes%ROWTYPE;
BEGIN
-- Usar %TYPE
SELECT nome, email INTO v_nome_cliente, v_email_cliente
FROM clientes WHERE cliente_id = 1;
-- Usar %ROWTYPE
SELECT * INTO v_cliente
FROM clientes WHERE cliente_id = 1;
DBMS_OUTPUT.PUT_LINE('Cliente: ' || v_cliente.nome);
DBMS_OUTPUT.PUT_LINE('Email: ' || v_cliente.email);
END;
/ Estruturas de Controle
IF, CASE, LOOPs e estruturas condicionais para controle de fluxo.
IF / ELSIF / ELSE
Estruturas condicionais para tomada de decisão
IF Simples
DECLARE
v_salario NUMBER := 5000;
v_bonus NUMBER;
BEGIN
IF v_salario > 3000 THEN
v_bonus := v_salario * 0.10;
END IF;
DBMS_OUTPUT.PUT_LINE('Bônus: ' || v_bonus);
END;
/ IF / ELSE
DECLARE
v_nota NUMBER := 7.5;
v_status VARCHAR2(20);
BEGIN
IF v_nota >= 7 THEN
v_status := 'Aprovado';
ELSE
v_status := 'Reprovado';
END IF;
DBMS_OUTPUT.PUT_LINE('Status: ' || v_status);
END;
/ LOOPs
Estruturas de repetição: LOOP, WHILE, FOR
FOR LOOP
BEGIN
-- FOR com números
FOR i IN 1..10 LOOP
DBMS_OUTPUT.PUT_LINE('Número: ' || i);
END LOOP;
-- FOR com cursor implícito
FOR reg IN (SELECT nome, salario FROM funcionarios WHERE rownum <= 5) LOOP
DBMS_OUTPUT.PUT_LINE(reg.nome || ' - R$ ' || reg.salario);
END LOOP;
END;
/ Cursors
Cursors para processar múltiplas linhas de uma query.
Cursor Explícito
Cursor declarado explicitamente para controle total
Cursor Básico
DECLARE
-- Declarar cursor
CURSOR c_clientes IS
SELECT cliente_id, nome, email
FROM clientes
WHERE ativo = 1;
-- Variável para armazenar linha
v_cliente c_clientes%ROWTYPE;
BEGIN
-- Abrir cursor
OPEN c_clientes;
-- Loop para processar linhas
LOOP
FETCH c_clientes INTO v_cliente;
EXIT WHEN c_clientes%NOTFOUND;
DBMS_OUTPUT.PUT_LINE('Cliente: ' || v_cliente.nome);
END LOOP;
-- Fechar cursor
CLOSE c_clientes;
END;
/ Procedures e Functions
Criar procedures e functions reutilizáveis no banco de dados.
CREATE PROCEDURE
Criar procedures para executar lógica de negócio
Procedure Simples
-- Criar procedure
CREATE OR REPLACE PROCEDURE prc_atualizar_preco (
p_produto_id IN NUMBER,
p_novo_preco IN NUMBER
) AS
BEGIN
UPDATE produtos
SET preco = p_novo_preco,
data_atualizacao = SYSDATE
WHERE produto_id = p_produto_id;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Preço atualizado com sucesso');
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Produto não encontrado');
ROLLBACK;
END;
/
-- Executar procedure
BEGIN
prc_atualizar_preco(123, 99.90);
END;
/ CREATE FUNCTION
Criar functions que retornam valores
Function Simples
-- Criar function
CREATE OR REPLACE FUNCTION fnc_calcular_desconto (
p_valor IN NUMBER,
p_percentual IN NUMBER
) RETURN NUMBER AS
v_desconto NUMBER;
BEGIN
v_desconto := p_valor * (p_percentual / 100);
RETURN v_desconto;
END;
/
-- Usar function em SELECT
SELECT
produto_id,
nome,
preco,
fnc_calcular_desconto(preco, 10) AS desconto,
preco - fnc_calcular_desconto(preco, 10) AS preco_final
FROM produtos;
/ Packages
Agrupar procedures, functions e variáveis relacionadas em packages.
CREATE PACKAGE
Criar package para organizar código PL/SQL
Package Básico
-- Especificação do Package
CREATE OR REPLACE PACKAGE pkg_vendas AS
CONSTANT c_taxa_imposto NUMBER := 0.10;
PROCEDURE prc_processar_venda (
p_cliente_id IN NUMBER,
p_valor IN NUMBER
);
FUNCTION fnc_calcular_total (
p_valor IN NUMBER
) RETURN NUMBER;
END pkg_vendas;
/
-- Corpo do Package
CREATE OR REPLACE PACKAGE BODY pkg_vendas AS
PROCEDURE prc_processar_venda (
p_cliente_id IN NUMBER,
p_valor IN NUMBER
) AS
BEGIN
INSERT INTO vendas (cliente_id, valor, data_venda)
VALUES (p_cliente_id, p_valor, SYSDATE);
COMMIT;
END prc_processar_venda;
FUNCTION fnc_calcular_total (
p_valor IN NUMBER
) RETURN NUMBER AS
BEGIN
RETURN p_valor + (p_valor * c_taxa_imposto);
END fnc_calcular_total;
END pkg_vendas;
/ Triggers
Triggers para executar ações automaticamente em eventos DML.
CREATE TRIGGER
Criar triggers para automatizar ações
Trigger BEFORE INSERT
-- Trigger antes de inserir
CREATE OR REPLACE TRIGGER trg_clientes_before_insert
BEFORE INSERT ON clientes
FOR EACH ROW
BEGIN
IF :NEW.cliente_id IS NULL THEN
SELECT seq_clientes.NEXTVAL INTO :NEW.cliente_id FROM DUAL;
END IF;
:NEW.data_cadastro := SYSDATE;
END;
/ Exception Handling
Tratamento de erros e exceções em PL/SQL.
Exceções Pré-definidas
Tratar exceções padrão do Oracle
Exception Handling
DECLARE
v_salario NUMBER;
BEGIN
SELECT salario INTO v_salario
FROM funcionarios
WHERE funcionario_id = 999;
DBMS_OUTPUT.PUT_LINE('Salário: ' || v_salario);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Funcionário não encontrado');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Múltiplos registros encontrados');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Erro: ' || SQLERRM);
END;
/