Não é possível eliminar a restrição inexistente e não pode criá-la

16

Ao testar alguns scripts de migração com uma cópia dos dados de produção (os scripts funcionam bem com os dados de desenvolvimento), encontrei uma situação curiosa. Um CONSTRAINT mudou, por isso estou emitindo comandos DROP + ADD:

ALTER TABLE A_DUP_CALLE
DROP CONSTRAINT A_DUP_CALLE_UK1;

ALTER TABLE A_DUP_CALLE
ADD CONSTRAINT A_DUP_CALLE_UK1 UNIQUE (
    CONTROL_ID,
    CALLE_AYTO_DUPL
)
ENABLE;

O comando DROP funcionou bem, mas o comando ADD falhou. Agora, estou em um círculo vicioso. Não consigo descartar a restrição porque ela não existe (a queda inicial funcionou conforme o esperado):

ORA-02443: Não é possível eliminar a restrição - restrição inexistente

E não posso criá-lo porque o nome já existe:

ORA-00955: nome já é usado por um objeto existente

Digito A_DUP_CALLE_UK1na caixa de pesquisa do desenvolvedor SQL e ... aí está! Proprietário, nome da tabela, paisagem da tabela ... tudo corresponde: não é um objeto diferente com o mesmo nome, é a minha restrição original. A tabela aparece nos detalhes da restrição, mas a restrição não aparece nos detalhes da tabela.

Minhas perguntas:

  • Qual a explicação para isso?
  • Como garantir que isso não aconteça quando eu fizer a atualização real no servidor ativo?

(O servidor é 10g XE, não tenho reputação suficiente para criar a tag.)

Álvaro González
fonte
Talvez ele tenha sido criado como outro tipo de objeto e não como uma restrição única? Talvez índice único ..
Marian
A criação inicial poderia ter sido executada com aspas ao redor do nome da tabela? Isso tornaria o nome sensível a maiúsculas e minúsculas. Nesse caso, você pode usar aspas e o mesmo caso.
Adam Butler

Respostas:

13

Suponho que eu diria que Marian está certa e isso é causado por um índice e restrição únicos com o mesmo nome, por exemplo:

create table t( k1 integer, k2 integer, 
                constraint u1 unique(k1,k2) using index(create unique index u1 on t(k1,k2)),
                constraint u2 unique(k2,k1) using index u1);

select count(*) from user_indexes where index_name='U1';

COUNT(*)               
---------------------- 
1  

alter table t drop constraint u1;

select count(*) from user_indexes where index_name='U1';

COUNT(*)               
---------------------- 
1  

Normalmente, quando você adiciona uma restrição exclusiva, um índice exclusivo com o mesmo nome é criado - mas o índice e a restrição não são a mesma coisa. Dê uma olhada all_indexespara ver se há um índice chamado A_DUP_CALLE_UK1e tente descobrir se ele é usado por outra coisa antes de soltá-lo!

Jack Douglas
fonte
Esse foi o problema. O arquivo de despejo gerado pelo expcomando contém uma CREATE UNIQUE INDEX "A_DUP_CALLE_UK1" ...instrução que não está presente no conjunto de scripts original.
Álvaro González
6

Parece muito estranho.

Você pode correr:

 SELECT *
 FROM user_objects
 WHERE object_name = 'A_DUP_CALLE_UK1'

para verificar se de que tipo de objeto a Oracle se queixa. Em seguida, você pode executar a instrução DROP apropriada para isso.

A única outra coisa em que consigo pensar é soltar a tabela completamente usando-a DROP TABLE A_DUP_CALLE CASCADE CONSTRAINTSpara se livrar de tudo o que pertence a ela e depois recriá-la completamente.

Se a tabela contiver dados valiosos, você poderá fazer um backup deles antes:

CREATE TABLE old_data
AS
SELECT *
FROM A_DUP_CALLE;

Depois de recriar a tabela, você pode fazer

INSERT INTO A_DUP_CALLE (col1, col2, col3) 
SELECT col1, col2, col3
FROM old_data

para restaurar os dados.

um cavalo sem nome
fonte
4

Eu tive o mesmo problema há alguns minutos atrás ... e encontrei uma explicação.

Ao criar uma Chave Primária, o Oracle cria dois objetos: uma restrição e um índice, que controla a parte "ÚNICA".

Ao eliminar a restrição, o índice permanece lá, usando o mesmo nome do índice, portanto, se você executar apenas

alter table t drop constraint u1;

Você eliminará apenas a restrição. Para soltar o índice, você precisará executar

drop index u1;

Isso deve fazer o trabalho. Como alternativa, você pode executar esses dois comandos ao mesmo tempo com o comando

alter table t drop constraint u1 including indexes;
Cristian Meneses A
fonte
qual db? incluindo não funciona no Oracle
Derick
1

A restrição de chave primária vem com o índice. Você elimina a restrição, mas não o índice. Verifica:

select * from ALL_OBJECTS where OBJECT_NAME = 'PK_TBL_CONSTR';

e você vê OBJECT_TYPEé INDEX.

O mesmo acontece com os dois:

alter table TBL drop constraint PK_TBL_CONSTR;
drop index PK_TBL_CONSTR;
gavenkoa
fonte
1

Faça isso

ALTER TABLE A_DUP_CALLE
DROP CONSTRAINT "A_DUP_CALLE_UK1";

Vai funcionar.

IMAGEM: insira a descrição da imagem aqui

Sachin
fonte
Não, não vai funcionar. Sua declaração é exatamente a mesma que a primeira declaração da pergunta:ALTER TABLE A_DUP_CALLE DROP CONSTRAINT A_DUP_CALLE_UK1;
a_horse_with_no_name
Funcionou na verdade. Eu estava tendo o mesmo problema desde o meio dia de hoje e, procurando a solução, me deparei com isso. Às vezes, as restrições podem ter sido criadas com distinção entre maiúsculas e minúsculas; nesse caso, você precisará colocar o nome da restrição entre aspas duplas quando a soltar.
Sachin
E funcionou para mim. Eu não havia nomeado explicitamente as restrições, portanto, o sistema forneceu seu próprio nome gerado Relationship142e outro nome de NOT NULLrestrição foi dado SYS_C0015910. Então SYS_C0015910foi excluído com sucesso com uma simples consulta ALTER, mas Relationship142precisava de aspas
Sachin
11
Você criou as restrições usando aspas duplas, por exemplo: alter table ... add constraint "Relationship143" ... "Relationship143"é realmente um nome diferente de RELATIONSHIP143. Mas "RELATIONSHIP143"e RELATIONSHIP143são idênticos
a_horse_with_no_name
2
O Oracle (o banco de dados) nunca criará um nome como "Relationship143"ele mesmo. Provavelmente foi uma das suas ferramentas que fez isso. Enfim: como está, sua resposta está simplesmente errada no contexto da pergunta original.
A_horse_with_no_name