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


12

私は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")

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

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

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

回答:


17

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

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

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
);

「4つの列を持つテーブルを作成し、1は他の人がすることができ、主キー(PK)、次のようになります。この定義には、次のおおよそのPostgreSQLを伝えるNULL。新しい行が挿入されている場合は、チェックDataIDしてAddress、彼らは非NULL値が含まれている場合(: 27856)は言う、その後、チェックTable1のためにDataIDTable2のためにAddress。これらのテーブルには、そのような値が存在しない場合は、エラーを返します。」あなたが最初に見たこの最後のポイント:

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

その行が必要な場合は、最初Table1with DataID = 27856に行を挿入してから、に挿入してみてくださいTable3これがあなたが望むものではないと思われる場合は、何を達成したいかを数文で説明してください。そうすれば、優れた設計を支援できます。


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

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

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

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

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

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

ID        DataID           Address             Data
123       3216547          1234567890454       654897564134569

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


あなたの貴重な提案をありがとう。私はあなたの提案に基づいてより良いデザインに努めます。これで最初のエラーが解決されました。
Haseena、

0

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

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

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

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.