Problema:
Em um pacote PL/SQL grande, tenho várias INSERT
instruções e, às vezes, encontro o ORA-00947: not enough values
erro quando o número de valores não corresponde às colunas. Quero capturar esse erro, registrá-lo e permitir que o pacote continue com operações subsequentes (como inserir em outras tabelas), sem invalidar o pacote inteiro.
Código:
CREATE TABLE RFTB_DAILY_GL_BAL (
col1 NUMBER,
col2 VARCHAR2(20),
col3 DATE
);
DECLARE
BEGIN
BEGIN
INSERT INTO RFTB_DAILY_GL_BAL-- (col1, col2, col3)
SELECT 1 FROM dual; -- Causes ORA-00947
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('error found: ' || SQLERRM);
END;
-- Proceed to next insertion
dbms_output.put_line('Continuing to next step...');
-- Simulate another operation
INSERT INTO another_table (col1, col2) VALUES ('test', SYSDATE);
END;
/
Pergunta:
Essa é uma maneira eficiente de capturar e manipular ORA-00947
sem parar a execução de todo o pacote PL/SQL? Alguma sugestão para melhorar essa abordagem?
Razão:
Estou na fase de desenvolvimento e frequentemente crio ou removo colunas com base em requisitos em evolução (sim, eu sei que não é o ideal, mas prazos curtos tornam isso necessário). Por isso, mesmo se eu especificar colunas no INSERT
, não posso confiar que a estrutura da coluna permanecerá constante. Preciso capturar ORA-00947: not enough values
e continuar a execução sem invalidar o pacote.
Realisticamente, não.
ORA-00947 é um erro de compilação PL/SQL. O código que você postou não compila. Como ele não compila, ele não pode ser executado, então ele nunca pode alcançar o manipulador de exceção. Você não pode capturar erros de compilação com um manipulador de exceção de tempo de execução.
Tecnicamente, sim.
Dito isso, você pode usar SQL dinâmico para adiar a compilação até o tempo de execução, o que mudará seu erro de compilação para um erro de tempo de execução que você pode capturar. Na prática, você não gostaria de fazer isso porque isso torna muito mais demorado escrever, depurar e manter seu código.
Então você poderia fazer algo como
Mas, na prática, é muito improvável que mover tudo o que você deseja capturar em tempo de execução para SQL dinâmico seja uma boa escolha.
É muito mais provável que você seria melhor servido escrevendo mais código modular. Se você tem um pacote que lida com todo o DML em
RFTB_DAILY_GL_BAL
, por exemplo, então você sabe que se você for modificar a estrutura daquela tabela, você precisaria modificar a implementação daquele pacote. Você poderia tornar essas implementações compatíveis com versões anteriores se você quisesse, para que o código de chamada pelo menos continuasse a compilar sem nenhuma alteração.Em um pacote, isso nunca funcionará usando sql regular. O "ORA-00947: valores insuficientes" não é levantado ao executar o pacote, ele é levantado quando o pacote tenta recompilar. Um pacote com uma instrução sql inválida é inválido e não pode ser executado. Uma alternativa é usar sql dinâmico com
EXECUTE IMMEDIATE
e definir uma exceção para o ORA-00947. Então capture a exceção.Exemplo: