外部キー制約を含む列を既存のテーブルに追加する方法は?


11

次の表があります。

CREATE TABLE users (id int PRIMARY KEY);

-- already exists with data
CREATE TABLE message ();

messagesテーブルをどのように変更しますか?

  1. という新しい列senderが追加されます
  2. テーブルをsender参照する外部キーはどこusersですか

これはうまくいきませんでした

# ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;
ERROR:  column "sender" referenced in foreign key constraint does not exist

このステートメントは列も作成しませんか?


3
参照する前に列を作成する必要があります。ここでALTER TABLEのドキュメントも読んでみて、例に非常に注意を払います。
Kassandry 2016年

ハッサン、私はこの質問をクリーンアップしてDDLを使用し、機能しなかったものを削除しました。これが質問に答えるかどうかを確認してください:dba.stackexchange.com/a/202564/2639。これらの編集は自由に拒否してください。後世のためにこれを片付けたかっただけです。
エヴァンキャロル

回答:


18

比較的簡単なこと-別のステップを追加するだけです。

FOREIGN KEY列は存在している必要があり、それにするためにFK。私は次のことをしました(ここドキュメントから):

CREATE TABLE x(t INT PRIMARY KEY);

CREATE TABLE y(s INT);

ALTER TABLE y ADD COLUMN z INT;    

ALTER TABLE y
  ADD CONSTRAINT y_x_fkey FOREIGN KEY (z)
      REFERENCES x (t)
      ON UPDATE CASCADE ON DELETE CASCADE;

注意すべきいくつかの点:

常に、外部キーに意味のある名前を付けてください。キー「SYS_C00308108」が違反されていると言われてもあまり役に立ちません。フィドルを参照してくださいここで)キー名はフィドルにフィドルによって異なりますこのような状況の下で、Oracleの行動のために、しかし、SYS _...で始まるいくつかの任意の文字列です

あなたの声明を考慮してください:

ALTER TABLE message ADD FOREIGN KEY (sender) REFERENCES users;

RDBMSが、参照されたフィールドと一致するデータ型を使用して、必要なフィールドを自動的に作成できる場合、これは「便利」です。私が言えることは、DDLの変更はめったに使用されない操作であり(少なくともそうである必要があります)、定期的に実行する必要のある操作ではないということです。また、すでにかなりの量のドキュメントを追加するリスクもあります。

少なくともPostgreSQLは適切な処理を試みます。テーブル名とFOREIGN KEYフィールド名を連結し、_fkeyさらにDETAIL: Key (sender_id)=(56) is not present in table "user_".、人間にとって意味のあるものを追加することもできますここのフィドルを参照してください。


2
外部キーに名前を付けることはありません。それらは自動的に名前が付けられ、通常は非常に便利です。たとえば、そのコンテキストのデフォルト名は"y_z_fkey"です。これはy_x_fkey、違反によってエラーが発生ている列に挿入ている列が示されないためよりも適切な名前だと思います。どこを指しているのか気になりません。一般的なルールとして、次のことを行う必要があり決してあなたFKEYSに名前を付けないとPostgreSQLのデフォルトは、それを処理しましょう。
エヴァンキャロル

また、ON UPDATE CASCADE ON DELETE CASCADE;特に理由なしに、例のデフォルトをオーバーライドしたくない場合もあります。これは例をより複雑にし、それが何であるかを説明する気になりません。私は通常、削除をカスケードすることを望んでいません。
エヴァンキャロル

1
会社/プロジェクトが決定した規則に従って、私は常に FKに名前を付けます。y_x_fkeyor y_z_fkeyまたはであるかどうかはx__y_FK、一貫性がある限り、あまり問題ではありません。
ypercubeᵀᴹ

あなたが契約しているなら、私はこれに非常に同意します-規則を選んでそれに固執する、および/または以前にシステムで使用された/使用された規則に確実に準拠するようにしてください。
Vérace

@EvanCarroll- PostgreSQLの規則がプロジェクトの規則であるか、 PostgreSQLではない可能性のあるシステムで以前に決定された規則である場合 -システムは、たとえばPostgreSQLの規則を持たない可能性のあるOr​​acleまたは他のシステムで開始されている可能性があります。エラーが発生した場合、x_y_z_fkが最大限の情報を提供する可能性があると主張できます。何かを選んでそれに固執することが私のモットーですが、1つのRDBMSが(どんなに優れていても)規則を決めないようにしてください!
Vérace

8

なぜ誰もがこれを2つのステップで実行する必要があると言っているのかわかりません。実際、そうではありませんFOREIGN KEY設計上、列が存在すると想定して、列が存在しない場合にエラーをスローするを追加しようとしました。を追加COLUMNする場合、FOREIGN KEYで作成時に明示的にオンにすることができますREFERENCES

ALTER TABLE message
  ADD COLUMN sender INT
  REFERENCES users;  -- or REFERENCES table(unique_column)

正常に動作します。ここの構文を見ることができます、ALTER TABLE

ALTER TABLE [ IF EXISTS ] [ ONLY ] name [ * ]
action [, ... ]

「アクション」として、

ADD [ COLUMN ] [ IF NOT EXISTS ] column_name data_type [ COLLATE collation ] [ column_constraint [ ... ] ]

これらの例はドキュメントにもあります

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address);

ALTER TABLE distributors
  ADD CONSTRAINT distfk
  FOREIGN KEY (address)
  REFERENCES addresses (address)
  NOT VALID;

しかし、自動命名と主キーの解決に頼ることができるため、これらすべては必要ありません(table-nameのみが指定されている場合は、主キーを参照しています)。


0

CASE1: 新しいテーブルの作成中に外部キーを作成する必要がある場合

CREATE TABLE table1(
id SERIAL PRIMARY KEY,
column1 varchar(n) NOT NULL,
table2_id SMALLINT REFERENCES table2(id)
); 

上記のコマンドは、「table1」という名前のテーブルと、「id」(主キー)、「column1」、「table2_id」(table2のid列を参照するtable1の外部キー)という名前の3つの列を持つテーブルを作成します。

DATATYPE 'serial'は、このデータ型を自動生成列として使用する列を作成します。テーブルに値を挿入する場合、この列についてまったく言及する必要はありません。または、値の場所に引用符なしで 'default'を指定できます。

主キー列は常に値「tablename_pkey」を持つテーブルのインデックスに追加されます。

テーブルの作成時に外部キーが追加されると、パターン '(present_table_name)_(foreign_key_id_name)_fkey'でCONSTRAINTが追加されます。

外部キーを追加するときは、列名の横にキーワード「REFERENCES」を入力する必要があります。これは、この列がテーブルを参照することをpostgresに伝え、次に参照の横に参照用のテーブルを指定する必要があるためです。参照されるテーブルの列名。通常、外部キーは主キー列として指定されます。

ケース2: 既存の列の既存のテーブルへの外部キーが必要な場合

ALTER TABLE table1
ADD CONSTRAINT table1_table2_id_id_fkey
FOREIGN KEY (table2_id) REFERENCES table2(id);

注:FOREIGN KEYとREFERENCES tabel2の後のブラケット '()'は必須です。そうでない場合、postgresはエラーをスローします。


0

私は問題を知っています。列名が異なります。たぶん1つの列では、列名の後にスペースが追加されるので、列名の名前が正確に同じであることを確認してください。


1
OPは尋ねました:このステートメントは列も作成しませんか?それで、彼がそれが起こることを期待したことは明らかです。
ローレンツアルベ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.