Olá, Adriano. Como vai?
Parabéns pela resolução do exercício! O seu código ficou excelente, muito bem estruturado e a lógica aplicada está impecável.
O uso da função NVL foi uma excelente prática de programação defensiva. Garantir que valores nulos sejam tratados como 0 evita erros inesperados de execução (como tentar fazer cálculos com NULL), o que é fundamental ao lidar com bancos de dados em ambientes reais de produção.
Para agregar ainda mais valor ao seu projeto e complementar sua solução, quero deixar duas sugestões de boas práticas que são muito utilizadas no dia a dia por desenvolvedores PL/SQL:
1. Tratamento de Exceções (Exceptions)
No cenário atual, o seu SELECT ... INTO funciona perfeitamente porque o v_ID := 2 existe na tabela. Contudo, se por acaso um ID inexistente for passado como parâmetro, o Oracle irá disparar um erro do tipo NO_DATA_FOUND.
Para deixar sua procedure ainda mais robusta, você pode adicionar um bloco de EXCEPTION no final dela. Veja como ficaria:
CREATE OR REPLACE PROCEDURE CALCULO_IMPOSTO
(p_ID IN PRODUTO_VENDA_EXERCICIO.ID%type,
p_VALOR_IMPOSTO OUT NUMBER) IS
v_PRECO PRODUTO_VENDA_EXERCICIO.PRECO%type;
v_QUANTIDADE PRODUTO_VENDA_EXERCICIO.QUANTIDADE%type;
v_PERCENTUAL_IMPOSTO PRODUTO_VENDA_EXERCICIO.PERCENTUAL_IMPOSTO%type;
BEGIN
SELECT PRECO, QUANTIDADE, PERCENTUAL_IMPOSTO
INTO v_PRECO, v_QUANTIDADE, v_PERCENTUAL_IMPOSTO
FROM PRODUTO_VENDA_EXERCICIO WHERE ID = p_ID;
p_VALOR_IMPOSTO := NVL(v_PRECO,0) * NVL(v_QUANTIDADE,0) * (NVL(v_PERCENTUAL_IMPOSTO,0) / 100);
EXCEPTION
WHEN NO_DATA_FOUND THEN
p_VALOR_IMPOSTO := 0;
DBMS_OUTPUT.PUT_LINE('Aviso: O ID ' || p_ID || ' não foi encontrado.');
WHEN OTHERS THEN
p_VALOR_IMPOSTO := 0;
DBMS_OUTPUT.PUT_LINE('Erro inesperado: ' || SQLERRM);
END;
2. Formatação da Saída de Valores
No bloco anônimo de teste, você concatenou o texto com o valor bruto. Como estamos lidando com dinheiro, uma dica legal para os seus próximos relatórios ou testes é utilizar a função TO_CHAR combinado com uma máscara de formato. Isso ajuda a garantir que casas decimais apareçam corretamente (como R$750,00).
Você pode alterar a linha do seu DBMS_OUTPUT para:
DBMS_OUTPUT.PUT_LINE('O Valor do imposto do produto: ' || v_ID || ' é de R$' || TO_CHAR(v_VALOR_IMPOSTO, '999G999D99'));
Isso formata o número no padrão monetário de forma bem elegante.
Seu resultado bateu certinho com os dados da tabela, mostrando que você compreendeu muito bem os conceitos de parâmetros IN e OUT. Continue com esse ótimo desempenho!
Espero que possa ter lhe ajudado!