web-dev-qa-db-ja.com

「更新時」および「削除時」オプションのPostgres外部キーはどのように機能しますか?

これらの関数が何をするのか、そしていつそれらを使用するのが適切かについて、誰かが明確な説明/例を提供できますか?

22
meleyal

マニュアル ..から直接.

外部キーは、どの製品にも関係のない注文の作成を許可しないことを私たちは知っています。しかし、それを参照する注文が作成された後に製品が削除された場合はどうなりますか? SQLではそれも処理できます。直感的に、いくつかのオプションがあります。

参照されている製品の削除を禁止する

注文も削除します

他に何かありますか?

CREATE TABLE order_items (
 product_no integer REFERENCES products ON DELETE RESTRICT,
 order_id integer REFERENCES orders ON DELETE CASCADE,
 quantity integer,
 PRIMARY KEY (product_no, order_id)
);

削除の制限とカスケードは、最も一般的な2つのオプションです。 RESTRICTは、参照された行の削除を防ぎます。 NO ACTIONは、制約がチェックされたときに参照行がまだ存在する場合、エラーが発生することを意味します。これは、何も指定しない場合のデフォルトの動作です。 (これら2つの選択肢の本質的な違いは、NO ACTIONを使用すると、トランザクションの後半までチェックを延期できるのに対し、RESTRICTは許可しないことです。)CASCADEは、参照される行が削除されると、それを参照する行を自動的に削除するように指定します。同様に。他に2つのオプションがあります:SETNULLとSETDEFAULT。これらにより、参照される行が削除されると、参照する列がそれぞれnullまたはデフォルト値に設定されます。これらは、制約を遵守することを免除するものではないことに注意してください。たとえば、アクションでSET DEFAULTが指定されていても、デフォルト値が外部キーを満たさない場合、操作は失敗します。

ON DELETEと同様に、参照される列が変更(更新)されたときに呼び出されるONUPDATEもあります。可能なアクションは同じです。

編集:この関連する質問を確認することをお勧めします: SQL Serverでカスケードを使用する場合/理由 。質問/回答の背後にある概念は同じです。

28
matt b

ダオクの言うことは本当です...それはかなり便利かもしれません。一方、データベース内で自動的に発生することは、特にデータの削除に関しては、実際の問題になる可能性があります。将来的には、FKは通常、子供がいるときに親の削除を防止し、On Delete Cascadeを使用しても削除が防止されないだけでなく、数十のデータが大量に作成されることに気付かない可能性があります。カスケード削除のウォーターフォールのおかげで、他のテーブルはなくなります。

@アーサーのコメント。

データベースで「隠された」ことが頻繁に発生するほど、何が起こっているのかを誰もがうまく処理できる可能性が低くなります。トリガー(そしてこれは本質的にトリガーです)は、行を削除するという私の単純なアクションを引き起こし、データベース全体に幅広い結果をもたらす可能性があります。 Deleteステートメントを発行すると、17個のテーブルがトリガーと制約のカスケードの影響を受けますが、コマンドの発行者にはこれがすぐにはわかりません。 OTOH、親とそのすべての子の削除をプロシージャに配置すると、コマンドを発行したときに何が起こるかを誰もが正確に確認するのは非常に簡単で明確です。

それは私がデータベースをどれだけうまく設計するかとは全く関係がありません。これは、トリガーによって発生する運用上の問題と関係があります。

0
Mark Brady

PostGreSQLデータベースがあり、データベースから削除するユーザーがいて、その情報を他のテーブルから削除する必要がある場合は、OnDeleteを使用します。この方法では、1回の削除のみを行う必要があり、ON削除のあるFKは他のテーブルから情報を削除します。

ONUpdateでも同じことができます。テーブルを更新し、フィールドにOn UpdateのFKがある場合、FKに変更が加えられると、FKテーブルに通知されます。

0

カスケード削除またはカスケード更新のすべての作業を実行するメソッドを作成する代わりに、代わりに警告メッセージを作成することができます。車輪の再発明よりもはるかに簡単で、クライアント(およびコードを取得する新しい開発者)に明確になります

0
Jeff Edwards