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