web-dev-qa-db-ja.com

PostgreSQL-挿入/更新が外部キー制約に違反しています

私はpostgreSQLの新人です。 3つのテーブルがあり、1つのテーブルが他の2つのテーブルの主キーを参照しています。しかし、_Table3_にデータを挿入できませんでした。以下のコードを参照してください:

_DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);
_

エラー:テーブル "Table3"の挿入または更新が外部キー制約 "Table3_DataID_fkey"に違反しています詳細:キー(DataID)=(27856)がテーブル "Table1"に存在しません。

3つのテーブルにデータを挿入しようとすると、エラーが発生しました。 postgreSQLドキュメント を参照し、コードを次のように変更しました(残念ながら、別のエラーが表示されていました)。

_DROP TABLE Table1 CASCADE;
CREATE TABLE Table1(
  "DataID" bigint NOT NULL DEFAULT '0',
  "AdData" integer DEFAULT NULL,
  PRIMARY KEY ("DataID")
);

DROP TABLE IF EXISTS Table2 CASCADE;
CREATE TABLE Table2 (
  "Address" numeric(20) NOT NULL DEFAULT '0',
  "Value" numeric(20) DEFAULT NULL,
  PRIMARY KEY ("Address")
);

DROP TABLE IF EXISTS Table3 CASCADE; 
CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL REFERENCES Table1 ON DELETE RESTRICT,
  "Address" numeric(20) DEFAULT NULL REFERENCES Table2 ON DELETE CASCADE, 
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   PRIMARY KEY("DataID", "Address")
);
_

エラー:テーブル「Table3」の複数の主キーは使用できません。行65:PRIMARY KEY( "DataID"、 "Address")

助けてください...どうすれば参照を作成できますか?

IDUNIQUEに変更し、PRIMARY KEY ("ID")という行を削除しました。そのとき、次のような別のエラーが表示されます:

エラー:重複するキー値が一意の制約「Table3_pkey」に違反しています

11
Haseena

テーブルにいくつかの問題があります。あなたがそれらについて質問したので、私は最初に外部キーに対処しようとします:)

ただし、その前に、2つのテーブルセット(作成した最初の3つと、最初のセットを削除した後に作成した2つ目のセット)が同じであることを理解する必要があります。もちろん、2回目の試行での_Table3_の定義には構文エラーと論理エラーがありますが、基本的な考え方は次のとおりです。

_CREATE TABLE table3 (   
  "ID" bigint NOT NULL DEFAULT '0',   
  "DataID" bigint DEFAULT NULL,   
  "Address" numeric(20) DEFAULT NULL,   
  "Data" bigint DEFAULT NULL,
   PRIMARY KEY ("ID"),   
   FOREIGN KEY ("DataID") REFERENCES Table1("DataID") on delete cascade on update cascade,   
   FOREIGN KEY ("Address") REFERENCES Table2("Address") on delete cascade on update cascade
);
_

この定義は、おお​​よそPostgreSQLに次のように伝えます。「4つの列を持つテーブルを作成し、1つを主キー(PK)にし、その他をNULLにすることができます。新しい行が挿入される場合は、DataIDAddressを確認してください。 NULL値(27856など)の場合、DataID checkの_Table1_とAddressの_Table2_を確認してください。これらのテーブルにそのような値がない場合は、エラーを返します。 "あなたが最初に見たこの最後のポイント:

_ERROR: insert or update on table "Table3" violates foreign key constraint 
    "Table3_DataID_fkey" DETAIL: Key (DataID)=(27856) is not present in table "Table1".
_

とても単純です。_Table1_に行がない場合、_DataID = 27856_の場合、その行を_Table3_に挿入することはできません。

その行が必要な場合は、first _Table1_に_DataID = 27856_を使用して行を挿入し、次に_Table3_に挿入してみてください。 これがあなたが望むものではないと思われる場合は、達成したいことを数文で説明してください。そうすれば、優れた設計を支援できます。


そして今、他の問題について。

PKを次のように定義します

_CREATE all_your_tables (
    first_column NOT NULL DEFAULT '0',   
    [...]
    PRIMARY KEY ("ID"),  
_

主キーは、その中のすべての項目が互いに異なることを意味します。つまり、値はUNIQUEです。 DEFAULT列に静的なUNIQUE(_'0'_など)を指定すると、常に予期しない事態が発生します。これは、3番目のエラーメッセージで得られたものです。

さらに、_'0'_はテキスト文字列を意味しますが、数値(あなたの場合はbigintまたはnumeric)を意味しません。代わりに単純に_0_を使用してください(または、上で書いたように、まったく使用しないでください)。

最後のポイント(私はここでは間違っているかもしれません):_Table2_では、Addressフィールドがnumeric(20)に設定されています。同時に、それはテーブルのPKです。列名とデータ型は、このアドレスが将来変更される可能性があることを示しています。これが本当なら、それはPKにとって非常に悪い選択です。次のシナリオについて考えてみましょう。「1234567890454」というアドレスがあり、これは_Table3_のように子を持っています

_ID        DataID           Address             Data
123       3216547          1234567890454       654897564134569
_

さて、そのアドレスはたまたま別のものに変わっています。 _Table3_の子行を親の後に新しい住所にするにはどうすればよいですか? (これには解決策がありますが、多くの混乱を引き起こす可能性があります。)これが当てはまる場合は、ID列をテーブルに追加します。これには、実際の情報は含まれず、単に識別値として機能します(つまり、 、ID)。

16
dezso

それはすべて、データをどのように処理するかによって異なります。

最初の例-すべてのテーブルで一貫性のあるデータを保持したいが、Table1と一致しない値を挿入しようとしています。

2番目の例-一貫性のあるデータを持ちたくないが、何かを正確に知らないで、何か他のことを試みてください。テーブルに複数の主キーを含めることはできません。

3番目の例-あなたはまだ何を達成したいのかわからず、同じ値を複数回持つ可能性のある列にUNIQUE制約を設定します。

データを挿入したいだけの場合-最初の例で外部キー参照を取り除いてください。すべてのテーブルに一貫性のあるデータが必要な場合-データをクリーンアップしてから、外部キー制約を使用してテーブルに挿入します。

tl; dr:最初の例のコードを使用してTable3にデータを挿入します-Table3.DataIdに存在する欠損値をTable1.DataID列に挿入します。

0
BartekR