Da forma que está, se eu não tiver um ID 2 por exemplo apresenta erro, então eu ajustei para ficar dá seguinte forma:
CREATE OR REPLACE PROCEDURE atualizar_valor_total_imposto IS
v_numero_venda INTEGER;
v_cod_produto produto_venda_exercicio.cod_produto%TYPE;
v_valor produto_venda_exercicio.valor_total%TYPE;
v_quantidade produto_venda_exercicio.quantidade%TYPE;
v_preco produto_venda_exercicio.preco%TYPE;
v_percentual produto_venda_exercicio.percentual_imposto%TYPE;
BEGIN
SELECT COUNT(*)
INTO v_numero_venda
FROM produto_venda_exercicio;
FOR i IN 1..v_numero_venda+1 LOOP
BEGIN
SELECT cod_produto, quantidade, preco
INTO v_cod_produto, v_quantidade, v_preco
FROM produto_venda_exercicio
WHERE id = i;
v_percentual := retorna_imposto(v_cod_produto);
v_valor := v_quantidade * v_preco;
UPDATE produto_venda_exercicio
SET
valor_total = v_valor,
percentual_imposto = v_percentual
WHERE
id = i;
DBMS_OUTPUT.PUT_LINE('Registro ID: ' || i || ', Valor Total: ' || v_valor || ', Percentual de Imposto: ' || v_percentual);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Registro não encontrado para o ID ' || i);
END;
END LOOP;
COMMIT;
END;