web-dev-qa-db-ja.com

挿入中の一意制約違反:なぜですか? (Oracle)

テーブルに新しい行を作成しようとしています。テーブルには2つの制約があります。1つはキーフィールド(DB_ID)に、もう1つは値をいくつかのフィールドENVのいずれかに制約します。挿入を行うときに、キーフィールドを挿入しようとしているフィールドの1つとして含めませんが、このエラーが発生します。

unique constraint (N390.PK_DB_ID) violated

エラーの原因となるSQLは次のとおりです。

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', '')

私が見つけた唯一のことは、行が手動で挿入された場合、Oracleがすでに使用中のDB_IDを割り当てようとしている可能性です。このデータベースのデータは、本番データベースから何らかの形で復元/移動されましたが、その方法に関する詳細はわかりません。

何かご意見は?

15
Sean

おそらく、DB_ID列に値を指定していないため、その値は、テーブルで定義された挿入トリガーの前に行レベルで設定されています。そのトリガーは、おそらく、シーケンスから値を選択することです。

データは(おそらく最近)実稼働データベースから移動されたため、私の賭けは、データがコピーされたときに、シーケンスも変更されなかったことです。シーケンスは、現在エラーの原因となっているテーブルにある最大のDB_IDよりもはるかに低い値を生成していると思います。

この疑いを確認するには、トリガーを見てどのシーケンスが使用されているかを判断し、

SELECT <<sequence name>>.nextval
  FROM dual

そしてそれを比較する

SELECT MAX(db_id)
  FROM cmdb_db

私が疑うように、シーケンスがデータベースに既に存在する値を生成している場合、未使用の値を生成するまでシーケンスをインクリメントするか、INCREMENTを非常に大きな値に設定するように変更できます。 nextvalを1回、INCREMENTを1に戻します。

39
Justin Cave

主キーフィールドDB_IDの値を指定していないようです。それが主キーである場合、その列に一意の値を指定する必要があります。それを提供しない唯一の方法は、挿入時に値を提供するデータベーストリガーを作成することです。ほとんどの場合、シーケンスから派生します。

これが別のデータベースからの復元であり、この新しいインスタンスにシーケンスがある場合、値を再利用しようとしている可能性があります。古いデータに1〜1000の一意のキーがあり、現在のシーケンスが500である場合、既存の値が生成されます。このテーブルにシーケンスが存在し、それを使用しようとしている場合、テーブルの値をシーケンスの現在の値と調整する必要があります。

SEQUENCE_NAME.CURRVALを使用して、シーケンスの現在の値を確認できます(もちろん存在する場合)

1
Brett McCann

エラーは、DB内の既存の主キーを複製しているようです。 IDENTITYキーワードなどを使用して、SQLコードを変更して独自のプライマリキーを実装する必要があります。

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

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

); 
1