web-dev-qa-db-fra.com

Violation de contrainte unique lors de l'insertion: pourquoi? (Oracle)

J'essaie de créer une nouvelle ligne dans un tableau. Il y a deux contraintes sur la table - l'une est sur le champ clé (DB_ID), l'autre contraint une valeur à être l'une de plusieurs du champ ENV. Lorsque je fais une insertion, je n'inclus pas le champ clé comme l'un des champs que j'essaie d'insérer, mais j'obtiens cette erreur:

unique constraint (N390.PK_DB_ID) violated

Voici le SQL qui provoque l'erreur:

insert into cmdb_db 
   (narrative_name, db_name, db_type, schema, node, env, server_id, state, path) 
values 
   ('Test Database', 'DB', 'TYPE', 'SCH', '', 'SB01', 381, 'TEST', '')

La seule chose que j'ai pu trouver est la possibilité qu'Oracle essaie d'attribuer un DB_ID déjà utilisé si des lignes ont été insérées manuellement. Les données de cette base de données ont été en quelque sorte restaurées/déplacées d'une base de données de production, mais je n'ai pas les détails sur la façon dont cela a été fait.

Des pensées?

15
Sean

Vraisemblablement, puisque vous ne fournissez pas de valeur pour le DB_ID colonne, cette valeur est remplie par un niveau ligne avant le déclencheur d'insertion défini sur la table. Ce déclencheur, vraisemblablement, sélectionne la valeur dans une séquence.

Étant donné que les données ont été déplacées (probablement récemment) de la base de données de production, mon pari serait que lorsque les données ont été copiées, la séquence n'a pas été modifiée également. Je suppose que la séquence génère des valeurs bien inférieures à la plus grande DB_ID qui se trouve actuellement dans le tableau menant à l'erreur.

Vous pouvez confirmer cette suspicion en regardant le déclencheur pour déterminer quelle séquence est utilisée et en faisant un

SELECT <<sequence name>>.nextval
  FROM dual

et comparer cela à

SELECT MAX(db_id)
  FROM cmdb_db

Si, comme je le soupçonne, la séquence génère des valeurs qui existent déjà dans la base de données, vous pouvez incrémenter la séquence jusqu'à ce qu'elle génère des valeurs inutilisées ou vous pouvez la modifier pour définir le INCREMENT sur quelque chose de très grand, obtenez le nextval une fois, et redéfinissez INCREMENT sur 1.

39
Justin Cave

Il semble que vous ne fournissiez pas de valeur pour le champ de clé primaire DB_ID. S'il s'agit d'une clé primaire, vous devez fournir une valeur unique pour cette colonne. La seule façon de ne pas le fournir serait de créer un déclencheur de base de données qui, lors de l'insertion, fournirait une valeur, très probablement dérivée d'une séquence.

S'il s'agit d'une restauration à partir d'une autre base de données et qu'il existe une séquence sur cette nouvelle instance, il se peut qu'elle essaie de réutiliser une valeur. Si les anciennes données avaient des clés uniques de 1 à 1000 et que votre séquence actuelle est à 500, cela générerait des valeurs qui existent déjà. Si une séquence existe pour cette table et qu'elle essaie de l'utiliser, vous devrez rapprocher les valeurs de votre table avec la valeur actuelle de la séquence.

Vous pouvez utiliser SEQUENCE_NAME.CURRVAL pour voir la valeur actuelle de la séquence (si elle existe bien sûr)

1
Brett McCann

Votre erreur semble que vous dupliquez une clé primaire déjà existante dans votre base de données. Vous devez modifier votre code SQL pour implémenter sa propre clé primaire en utilisant quelque chose comme le mot clé IDENTITY.

CREATE TABLE [DB] (
    [DBId] bigint NOT NULL IDENTITY,
    ...

    CONSTRAINT [DB_PK] PRIMARY KEY ([DB] ASC),

); 
1
Christopher Rayl