web-dev-qa-db-fra.com

Impossible de supprimer une contrainte inexistante et de la créer non plus

En testant certains scripts de migration avec une copie des données de production (les scripts fonctionnent bien avec les données de développement), j'ai trouvé une situation curieuse. UNE CONTRAINTE a changé, donc j'émets des commandes 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;

La commande DROP a bien fonctionné mais celle ADD a échoué. Maintenant, je suis dans un cercle vicieux. Je ne peux pas supprimer la contrainte car elle n'existe pas (la suppression initiale a fonctionné comme prévu):

ORA-02443: Impossible de supprimer la contrainte - contrainte inexistante

Et je ne peux pas le créer car le nom existe déjà:

ORA-00955: le nom est déjà utilisé par un objet existant

J'écris A_DUP_CALLE_UK1 dans la boîte de recherche du développeur SQL et ... la voici! Propriétaire, nom de table, tablescape ... tout concorde: ce n'est pas un objet différent avec le même nom, c'est est ma contrainte d'origine. Le tableau apparaît dans les détails de la contrainte mais la contrainte n'apparaît pas dans les détails du tableau.

Mes questions:

  • Quelle en est l'explication?
  • Comment puis-je m'assurer que cela ne se produira pas lorsque je ferai la mise à niveau réelle sur le serveur en direct?

(Le serveur est 10g XE, je n'ai pas assez de réputation pour créer la balise.)

16
Álvaro González

Je suppose que Marian a raison et cela est dû à un index et à une contrainte uniques ayant le même nom, par exemple:

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  

Normalement, lorsque vous ajoutez une contrainte unique, un index unique portant le même nom est créé, mais l'index et la contrainte ne sont pas la même chose. Jettes un coup d'oeil à all_indexes pour voir s'il existe un index appelé A_DUP_CALLE_UK1 et essayez de découvrir s'il est utilisé par autre chose avant de le déposer!

Semble très étrange.

Tu peux courir:

 SELECT *
 FROM user_objects
 WHERE object_name = 'A_DUP_CALLE_UK1'

pour vérifier de quel type d’objet se plaint Oracle. Ensuite, vous pouvez exécuter l'instruction DROP appropriée pour cela.

La seule autre chose à laquelle je peux penser est de supprimer complètement la table en utilisant DROP TABLE A_DUP_CALLE CASCADE CONSTRAINTS pour se débarrasser de tout ce qui appartient à cette table, puis la recréer complètement.

Si le tableau contient des données de valeur, vous pouvez en faire une sauvegarde avant:

CREATE TABLE old_data
AS
SELECT *
FROM A_DUP_CALLE;

Une fois que vous avez recréé la table, vous pouvez faire

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

pour restaurer les données.

6

J'ai eu le même problème il y a quelques minutes à peine ... et j'ai trouvé une explication.

En créant une clé primaire, Oracle crée deux objets: une contrainte et un index qui contrôlent la partie "UNIQUE".

En supprimant la contrainte, l'index reste là, en utilisant le même nom de l'index, donc si vous exécutez juste

alter table t drop constraint u1;

Vous ne supprimerez que la contrainte. Pour supprimer l'index, vous devrez exécuter

drop index u1;

Cela devrait faire le travail. Alternativement, vous pouvez exécuter ces deux commandes en même temps avec la commande

alter table t drop constraint u1 including indexes;
5
Cristian Meneses A

La contrainte de clé primaire est fournie avec l'index. Vous supprimez la contrainte mais pas l'index. Vérifier:

select * from ALL_OBJECTS where OBJECT_NAME = 'PK_TBL_CONSTR';

et vous voyez OBJECT_TYPE est INDEX.

Faites les deux:

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

Faites ceci

ALTER TABLE A_DUP_CALLE
DROP CONSTRAINT "A_DUP_CALLE_UK1";

Ça va marcher.

IMAGE: enter image description here

1
Sachin