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
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?
Olá Notria !
Sim, a lógica é a mesma. Só se atente ao fato de que a estrutura do TYPE deve ser compatível com a estrutura da tabela na qual os dados serão inseridos.
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.
Olá Luiz !
Dá uma olhada nesse artigo do Jefferson. É exatamente o que você precisa !
https://www.profissionaloracle.com.br/2016/11/06/forall-e-bulk-collect/
Abraço !