Importante

Você está vendo a versão anterior da nova experiência da Alura que estamos preparando para você. Em breve, ela ganha uma identidade visual novinha totalmente pensada em potencializar seus estudos!

1
resposta

MINHA RESOLUCAO

Bom dia a todos,

Gostei bastante desse exercicio, ele me fez utilizar várias coisas que aprendi ao decorrer do curso e agora no trabalho e abriu minha mente, as pesquisas após a montagem do exercicio foram pra corrigir alguns erros que não estavam de acordo com o que eu queria e aprendi e compreendi tudo que fiz. Estou feliz com a minha evolução desde o primeiro curso, quero evoluir cada vez mais.

Segue minha lógica. Consegui atualizar todos os valores automaticamente, além dos impostos, inclusive corrigindo o imposto que estava 100% anteriormente.


CREATE OR REPLACE PROCEDURE ATRIBUIR_VALOR_TOTAL_E_PERCENTUAL_IMPOSTO 
IS
    v_CONTADOR PRODUTO_VENDA_EXERCICIO.ID%type;
    v_QUANTIDADE PRODUTO_VENDA_EXERCICIO.QUANTIDADE%type;
    v_CODIGO PRODUTO_VENDA_EXERCICIO.COD_PRODUTO%type;
    v_PRECO PRODUTO_VENDA_EXERCICIO.PRECO%type;
    v_CATEGORIA PRODUTO_EXERCICIO.CATEGORIA%type;
    v_VALOR_TOTAL PRODUTO_VENDA_EXERCICIO.VALOR_TOTAL%type;
    v_PERCENTUAL_IMPOSTO NUMBER;
    v_MAX_ID NUMBER;
BEGIN  
    v_CONTADOR := 1;
    SELECT MAX(ID) INTO v_MAX_ID FROM PRODUTO_VENDA_EXERCICIO;
LOOP
    SELECT PV.QUANTIDADE, PV.PRECO, PV.COD_PRODUTO, PE.CATEGORIA
    INTO v_QUANTIDADE, v_PRECO, v_CODIGO, v_CATEGORIA
    FROM PRODUTO_VENDA_EXERCICIO PV, PRODUTO_EXERCICIO PE
    WHERE PV.COD_PRODUTO = PE.COD
    AND PV.ID = v_CONTADOR;
    
    v_VALOR_TOTAL := v_QUANTIDADE * v_PRECO;
    v_PERCENTUAL_IMPOSTO := RETORNA_IMPOSTO(v_CODIGO);
    
    UPDATE PRODUTO_VENDA_EXERCICIO SET VALOR_TOTAL = v_VALOR_TOTAL, PERCENTUAL_IMPOSTO = v_PERCENTUAL_IMPOSTO WHERE ID = v_CONTADOR;
    
    v_CONTADOR := v_CONTADOR + 1;
EXIT WHEN v_CONTADOR > v_MAX_ID;
END LOOP;
COMMIT;
END ATRIBUIR_VALOR_TOTAL_E_PERCENTUAL_IMPOSTO;
EXECUTE ATRIBUIR_VALOR_TOTAL_E_PERCENTUAL_IMPOSTO;
SELECT * FROM PRODUTO_VENDA_EXERCICIO;

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

1 resposta

Olá, Adriano. Como vai?

Parabéns pela excelente evolução e pela dedicação! Fico muito feliz em ler o seu relato. Esse sentimento de ver as peças se encaixando, pesquisar para corrigir comportamentos inesperados e conseguir automatizar processos complexos é o que define a trajetória de um ótimo desenvolvedor de banco de dados.

A sua PROCEDURE cumpriu perfeitamente o objetivo do exercício: percorreu os registros, calculou o VALOR_TOTAL multiplicando a quantidade pelo preço, buscou o imposto correspondente através da função RETORNA_IMPOSTO e atualizou a tabela de forma automatizada, como podemos ver no resultado limpo da sua imagem.

Como você está empolgado em evoluir e abrir ainda mais a mente para cenários do dia a dia no trabalho, vou trazer alguns pontos de reflexão técnica e boas práticas sobre o PL/SQL que vão elevar o nível do seu código:

1. O Perigo das "Lacunas" no ID (Gaps)

Na sua lógica, você utilizou um contador que inicia em 1 (v_CONTADOR := 1) e incrementa de um em um até alcançar o ID máximo (v_MAX_ID).

  • O que acontece se um registro for excluído? Imagine que o produto com ID = 5 seja deletado do banco de dados. Quando o seu laço LOOP chegar em v_CONTADOR := 5, o comando SELECT ... INTO tentará buscar o ID 5. Como ele não existe mais, o Oracle disparará imediatamente uma exceção do tipo NO_DATA_FOUND (Nenhum dado encontrado) e a sua procedure será interrompida antes de processar os IDs 6, 7 e 8.

2. Evoluindo para o Cursor FOR LOOP (Mais Seguro e Performático)

Para resolver o problema dos IDs excluídos e deixar o código muito mais limpo, o PL/SQL possui uma estrutura fantástica chamada Cursor FOR LOOP.

Com ela, você não precisa criar variáveis para cada coluna, não precisa buscar o ID máximo, não precisa controlar o contador manualmente e, o melhor de tudo, ele gerencia a abertura e o fechamento dos dados implicitamente. Veja como a sua lógica fica robusta e imune a buracos na numeração dos IDs:

CREATE OR REPLACE PROCEDURE ATRIBUIR_VALOR_TOTAL_E_PERCENTUAL_IMPOSTO IS
BEGIN  
    -- O FOR LOOP cria um cursor internamente e percorre linha por linha
    for reg in (
        SELECT PV.ID, PV.QUANTIDADE, PV.PRECO, PV.COD_PRODUTO
        FROM PRODUTO_VENDA_EXERCICIO PV
    ) loop
        
        -- Atualiza diretamente usando a linha atual do cursor (reg)
        UPDATE PRODUTO_VENDA_EXERCICIO 
        SET VALOR_TOTAL = reg.QUANTIDADE * reg.PRECO, 
            PERCENTUAL_IMPOSTO = RETORNA_IMPOSTO(reg.COD_PRODUTO) 
        WHERE ID = reg.ID;
        
    end loop;

    COMMIT;
END ATRIBUIR_VALOR_TOTAL_E_PERCENTUAL_IMPOSTO;

3. A Abordagem Puramente Relacional (SQL Puro)

Uma última reflexão: em bancos de dados, sempre que pudermos resolver uma operação em lote de uma única vez sem usar loops (linha por linha), o desempenho será infinitamente superior. No mercado de trabalho, para tabelas com milhões de linhas, loops podem ficar lentos devido ao que chamamos de Context Switching (o motor do PL/SQL conversando toda hora com o motor do SQL).

Você poderia obter exatamente o mesmo resultado de atualização sem nenhuma linha de loop, usando apenas um único comando UPDATE:

UPDATE PRODUTO_VENDA_EXERCICIO 
SET VALOR_TOTAL = QUANTIDADE * PRECO,
    PERCENTUAL_IMPOSTO = RETORNA_IMPOSTO(COD_PRODUTO);

Salvar esse código dentro de uma Procedure com essa única instrução executaria a alteração de todas as 8 linhas de forma instantânea!

Continue com esse brilho nos olhos e essa energia nas pesquisas. Você está no caminho certo para se tornar um especialista em bancos de dados!

Espero que possa ter lhe ajudado!