Procedure com BULK COLLECT limitado.
Boa tarde, estou tentando criar uma procedure utilizando o BULK COLLECT para uma melhor performance, porém está dando erro na linha 19,
Error: PLS-00394: wrong number of values in the INTO list of a FETCH statement
Line: 19
Text: FETCH c_TESTE BULK COLLECT INTO v_teste;
Poderiam me ajudar? Segue a procedure:
Error: PLS-00394: wrong number of values in the INTO list of a FETCH statement
Line: 19
Text: FETCH c_TESTE BULK COLLECT INTO v_teste;
Poderiam me ajudar? Segue a procedure:
CREATE OR REPLACE PROCEDURE CONSULTA_ITENS_MOVTO IS CURSOR c_TESTE IS SELECT M.DATAMOVTO, M.SEQMOVTO, M.CODIGOMARCAMAT, M.CODIGOMATINT, M.CODIGOLOCAL, M.QTDEITENSMOVTO, M.VALORITENSMOVTO FROM EST_ITENSMOVTO M WHERE M.DATAMOVTO BETWEEN '01-JAN-2019' AND '31-DEC-2019' ORDER BY M.DATAMOVTO, M.SEQMOVTO; TYPE r_TESTE IS TABLE OF EST_ITENSMOVTO%rowtype; v_teste r_TESTE; BEGIN OPEN c_TESTE; LOOP FETCH c_TESTE BULK COLLECT INTO v_teste; FORALL i IN 1..v_teste.COUNT INSERT INTO EST_TESTE(DATAMOVTO,SEQMOVTO,CODIGOMARCAMAT,CODIGOMATINT,CODIGOLOCAL,QTDEITENSMOVTO,VALORITENSMOVTO) VALUES (v_teste(i).DATAMOVTO,v_teste(i).SEQMOVTO,v_teste(i).CODIGOMARCAMAT,v_teste(i).CODIGOMATINT,v_teste(i).CODIGOLOCAL,v_teste(i).QTDEITENSMOVTO,v_teste(i).VALORITENSMOVTO); COMMIT; END LOOP; CLOSE c_TESTE; END CONSULTA_ITENS_MOVTO;
Breno
Curtidas 0
Melhor post
Arthur Heinrich
23/03/2023
Provavelmente o conjunto de colunas da tabela EST_ITENSMOVTO não está batendo com o número de colunas do cursor c_TESTE.
Você pode testar alterar a definição da variável de:
TYPE r_TESTE IS TABLE OF EST_ITENSMOVTO%rowtype;
Para:
TYPE r_TESTE IS TABLE OF c_TESTE%rowtype;
Você pode testar alterar a definição da variável de:
TYPE r_TESTE IS TABLE OF EST_ITENSMOVTO%rowtype;
Para:
TYPE r_TESTE IS TABLE OF c_TESTE%rowtype;
GOSTEI 1
Mais Respostas
Breno
23/03/2023
Provavelmente o conjunto de colunas da tabela EST_ITENSMOVTO não está batendo com o número de colunas do cursor c_TESTE.
Você pode testar alterar a definição da variável de:
TYPE r_TESTE IS TABLE OF EST_ITENSMOVTO%rowtype;
Para:
TYPE r_TESTE IS TABLE OF c_TESTE%rowtype;
Você pode testar alterar a definição da variável de:
TYPE r_TESTE IS TABLE OF EST_ITENSMOVTO%rowtype;
Para:
TYPE r_TESTE IS TABLE OF c_TESTE%rowtype;
Deu certo, muito obrigado!! Não tinha pensado nessa opção, anteriormente tentei fazer o TYPE utilizando a tabela de destino, mas não tinha dado certo, também.
GOSTEI 0
Arthur Heinrich
23/03/2023
Boa tarde, estou tentando criar uma procedure utilizando o BULK COLLECT para uma melhor performance, porém está dando erro na linha 19,
Error: PLS-00394: wrong number of values in the INTO list of a FETCH statement
Line: 19
Text: FETCH c_TESTE BULK COLLECT INTO v_teste;
Poderiam me ajudar? Segue a procedure:
Error: PLS-00394: wrong number of values in the INTO list of a FETCH statement
Line: 19
Text: FETCH c_TESTE BULK COLLECT INTO v_teste;
Poderiam me ajudar? Segue a procedure:
CREATE OR REPLACE PROCEDURE CONSULTA_ITENS_MOVTO IS CURSOR c_TESTE IS SELECT M.DATAMOVTO, M.SEQMOVTO, M.CODIGOMARCAMAT, M.CODIGOMATINT, M.CODIGOLOCAL, M.QTDEITENSMOVTO, M.VALORITENSMOVTO FROM EST_ITENSMOVTO M WHERE M.DATAMOVTO BETWEEN '01-JAN-2019' AND '31-DEC-2019' ORDER BY M.DATAMOVTO, M.SEQMOVTO; TYPE r_TESTE IS TABLE OF EST_ITENSMOVTO%rowtype; v_teste r_TESTE; BEGIN OPEN c_TESTE; LOOP FETCH c_TESTE BULK COLLECT INTO v_teste; FORALL i IN 1..v_teste.COUNT INSERT INTO EST_TESTE(DATAMOVTO,SEQMOVTO,CODIGOMARCAMAT,CODIGOMATINT,CODIGOLOCAL,QTDEITENSMOVTO,VALORITENSMOVTO) VALUES (v_teste(i).DATAMOVTO,v_teste(i).SEQMOVTO,v_teste(i).CODIGOMARCAMAT,v_teste(i).CODIGOMATINT,v_teste(i).CODIGOLOCAL,v_teste(i).QTDEITENSMOVTO,v_teste(i).VALORITENSMOVTO); COMMIT; END LOOP; CLOSE c_TESTE; END CONSULTA_ITENS_MOVTO;
Complementando a resposta anterior, referente à correção do erro, segue uma sugestão de boas práticas.
Seu código prevê que o dado seja copiado em blocos, uma vez que utiliza um loop, mas apresenta mais dois erros:
1 - Não prevê um critério de parada.
Um fetch após o último registro lido retorna 0 linhas, mas não aborta um loop/end loop. É necessário interromper o loop com uma checagem condicional, do tipo:
exit when v_teste.COUNT = 0;
2 - Não foi imposto um limite ao tamanho do fetch.
Caso o cursor retorne 1 bilhão de linhas, o banco tentará fazer o fetch de 1 bilhão de linhas de uma só vez. Isto não aumenta o desempenho e põe em risco a estabilidade da instância, seja pelo consumo excessivo de memória, tempo da transação ou consumo de undo.
O ideal é limitar o fetch, para garantir que as transações seja eficientes, mas pequenas e rápidas, evitando efeitos colaterais.
O objetivo do bulk collect/insert é minimizar o chaveamento de contexto entre a aplicação PL/SQL e o banco. A documentação sugere que utilizar blocos de 30 linhas pode ser suficiente, já que reduziria o chaveamento de contexto em aproximadamente 97%.
Eu costumo fazer uma estimativa do número de blocos afetados, utilizando um número aproximado de 100 blocos. Desta forma, em um insert como este, você preencherá completamente cerca de 99 blocos e o último terá algum espaço livre, que será preenchido pelo próximo insert. Isto faz com que o processamento duplicado de um bloco caia para cerca de 1% e você garante uma transação de 800 KB, que é bem pequena, rápida e libera os locks.
Ex.: Se o seu insert gera linhas de aproximadamente 150 bytes, o bloco utiliza 8 KB e a tabela foi configurada com PCT_FREE 10, por exemplo, cada bloco poderá conter: (8192 * 0.9)/150 ~49 linhas. Neste caso, eu utilizaria o fetch com um limite de 4900 ou 5000 linhas, para ficar redondo.
FETCH c_TESTE BULK COLLECT INTO v_teste limit 5000;
GOSTEI 0
Arthur Heinrich
23/03/2023
BEGIN OPEN c_TESTE; LOOP FETCH c_TESTE BULK COLLECT INTO v_teste LIMIT 5000; EXIT WHEN v_teste.COUNT = 0; FORALL i IN 1..v_teste.COUNT INSERT INTO EST_TESTE (DATAMOVTO, SEQMOVTO, CODIGOMARCAMAT, CODIGOMATINT, CODIGOLOCAL, QTDEITENSMOVTO, VALORITENSMOVTO) VALUES (v_teste(i).DATAMOVTO, v_teste(i).SEQMOVTO, v_teste(i).CODIGOMARCAMAT, v_teste(i).CODIGOMATINT, v_teste(i).CODIGOLOCAL, v_teste(i).QTDEITENSMOVTO, v_teste(i).VALORITENSMOVTO); COMMIT; END LOOP; CLOSE c_TESTE; END CONSULTA_ITENS_MOVTO;
GOSTEI 0