Pular para o conteúdo

Inserindo dados em uma tabela utilizando FORALL

Inserindo dados em uma tabela utilizando FORALL

Boa tarde !

Preciso alimentar uma tabela com dados que leio através de um SQL. Tentei usar insert normal mas ficou muito lento !

Verifiquei na internet e vi que o pessoal usa BULK COLLECTION mas não consegui montar algo funcional. Você pode me ajudar com alguma dica ?

Toledo


Toledo, como conversado anteriormente, irei demonstrar como podemos resolver esse seu problema utilizando FORALL. O objetivo desse post não é discutir sobre sua performance, e sim sobre como o implementar em  seu código.

Primeiramente, vamos criar as nossas tabelas para o nosso teste e inserir alguns dados: 

CREATE TABLE teste
(
 codigo    NUMBER,
 descricao VARCHAR2(2000)
)
/

INSERT INTO teste (codigo,descricao) VALUES (1,'DESCRICAO 1');
INSERT INTO teste (codigo,descricao) VALUES (2,'DESCRICAO 2');
INSERT INTO teste (codigo,descricao) VALUES (3,'DESCRICAO 3');
INSERT INTO teste (codigo,descricao) VALUES (4,'DESCRICAO 4');
INSERT INTO teste (codigo,descricao) VALUES (5,'DESCRICAO 5');
INSERT INTO teste (codigo,descricao) VALUES (6,'DESCRICAO 6');
INSERT INTO teste (codigo,descricao) VALUES (7,'DESCRICAO 7');
INSERT INTO teste (codigo,descricao) VALUES (8,'DESCRICAO 8');
INSERT INTO teste (codigo,descricao) VALUES (9,'DESCRICAO 9');
INSERT INTO teste (codigo,descricao) VALUES (10,'DESCRICAO 10');
INSERT INTO teste (codigo,descricao) VALUES (1,'DESCRICAO 1');
INSERT INTO teste (codigo,descricao) VALUES (2,'DESCRICAO 2');
INSERT INTO teste (codigo,descricao) VALUES (3,'DESCRICAO 3');
INSERT INTO teste (codigo,descricao) VALUES (4,'DESCRICAO 4');
INSERT INTO teste (codigo,descricao) VALUES (5,'DESCRICAO 5');
INSERT INTO teste (codigo,descricao) VALUES (6,'DESCRICAO 6');
INSERT INTO teste (codigo,descricao) VALUES (7,'DESCRICAO 7');
INSERT INTO teste (codigo,descricao) VALUES (8,'DESCRICAO 8');
INSERT INTO teste (codigo,descricao) VALUES (9,'DESCRICAO 9');
INSERT INTO teste (codigo,descricao) VALUES (10,'DESCRICAO 10');

CREATE TABLE teste2
(
 codigo    NUMBER,
 descricao VARCHAR2(2000)
)
/

Pronto, agora vamos ao nosso código:

DECLARE
  -- Variable

 TYPE v_tabData IS TABLE OF teste%ROWTYPE; 
  v_tabBulk v_tabData;
  x NUMBER := 0

  CURSOR c1 IS
  SELECT a.codigo
  ,a.descricao
  FROM teste a;

BEGIN
  -- Trunca a tabela
  DBMS_OUTPUT.put_line('Truncando a tabela...');
  DBMS_UTILITY.exec_ddl_statement('TRUNCATE TABLE teste2');

  OPEN c1;
  LOOP
  DBMS_OUTPUT.put_line('Iniciando leitura...'); 

  -- Fetch Collection
  FETCH c1 BULK COLLECT INTO v_tabBulk;

  DBMS_OUTPUT.put_line('Registro(s) a serem processados: ' || v_tabBulk.COUNT );

 -- Verifica se há registros
  IF v_tabBulk.COUNT > 0 
  THEN
  FORALL x IN 1..v_tabBulk.COUNT
  INSERT INTO teste2
  VALUES v_tabBulk(x);
  DBMS_OUTPUT.put_line('Registros processados...');

 END IF;

 EXIT WHEN c1%NOTFOUND;
  COMMIT;

 END LOOP;

 -- Não esqueça de fechar o seu cursor 🙂

 CLOSE c1;

 DBMS_OUTPUT.put_line('Fim do processo...');

EXCEPTION
  WHEN others THEN
  DBMS_OUTPUT.put_line('[ ERRO ] ' || DBMS_UTILITY.format_error_stack);

  IF SQL%ISOPEN
  THEN 
  -- Não esqueça de fechar o seu cursor 🙂
  CLOSE c1;

  END IF;

END;

Como a estrutura da tabela é idêntica ao do resultado do SELECT, pude utilizar o ROWTYPE da tabela como record do meu TYPE do tipo TABLE. O que facilita em muito o trabalho. Observe que estou lendo todos os dados da TABELA 1 e salvando na TABELA2.

Pronto Toledo, agora é só adaptar a suas necessidades. Espero que seja de grande ajuda a você e ao pessoal que acompanha o blog.

Um grande abraço

Sergio Willians

Sergio Willians

Sergio Willians é o fundador do GPO (Grupo de Profissionais Oracle) e possui quase 30 anos de experiência em tecnologias Oracle, sendo especialista em desenvolvimento Forms/Reports, PL/SQL e EBS (E-Business Suite) nos módulos Receivables, Payables e General Ledger. Atualmente trabalha na Scania Latin America, onde se dedica à área de integração de dados com Confluent Kafka. Sua paixão é compartilhar conhecimento com a comunidade Oracle, contribuindo para o crescimento e a excelência da plataforma.

Comentário(s) da Comunidade

  1. Avatar de Notria

    Olá Sérgio, boa tarde!
    Muito boa dica, parabéns!
    Preciso de um help. No caso do cursor ser referente a tabelas relacionadas como fazer? É a mesma lógica?

  2. Avatar de Luiz

    Olá. Por favor, usando FORALL, preciso executar dois updates, em tabelas diferentes, dentro do mesmo loop. Como ficaria a sintaxe do FORALL? eu preciso colocar um FORALL para cada update? Estou fazendo assim:
    loop
    forall i in first .. last
    execute immediate
    update 1

    forall i in firt .. last
    execute immediate
    update 2

    commit;
    end loop;

    se puder tirar essa dúvida, agradeço. obrigado.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

plugins premium WordPress