配列メンバーの外部キー制約?


27

ジョブの役割を含むテーブルがあるとします:

CREATE TABLE roles
(
  "role" character varying(80) NOT NULL,
  CONSTRAINT "role" PRIMARY KEY (role)
);

さらにテーブル、ユーザーがあり、各行(特定のユーザー)が任意の数のジョブロールを持つことができるとします。

CREATE TABLE users
(
  username character varying(12) NOT NULL,
  roles character varying(80)[] NOT NULL,
  CONSTRAINT username PRIMARY KEY (username)
);

の各メンバーがusers.roles[]roles.role に存在することを確認する必要があります。私が望むのは、users.roles[]ifがroles.roleを参照するような各メンバーの外部キー制約だと思われます。

これはpostgresでは不可能のようです。私はこれを間違った方法で見ていますか?これを処理するための推奨される「正しい」方法は何ですか?

回答:


20

配列外部キーのサポートは、それをPostgreSQL 9.3に組み込むことを目標に取り組んでいましたが、パフォーマンスと信頼性の問題のため、リリースの削減にはなりませんでした。9.4には取り組んでいないようです。

現時点では、「結合テーブル」を使用してm:n関係をモデル化する通常のリレーショナルアプローチに固執する必要があります。

CREATE TABLE user_roles (
   username character varying(12) references users(username),
   "role" character varying(80) references roles("role"),
   PRIMARY KEY(username, "role")
);

この場合も、ユーザー名/ロール名を結合テーブルに直接保存するのではなく、代理キーを使用することをお勧めします。初めてユーザーまたはロールの名前を変更したいときは、代理キーを使用して満足しています。置くだけuniqueに制約をroles."role"してusers.username


3

同僚のために似たようなものを作りました。基本的に、適切な制約を持つ各(ユーザー、ロール)ペアごとに1つの行を含む隠しテーブルを作成しました。ユーザーテーブルは、すべてのロールが配列にアセンブルされた非表示テーブルのビューでした。次に、適切なルールを追加して、ビューに挿入できるようにしました。方法は次のとおりです。

trailer=# create table harvester (id int unique, label text);
CREATE TABLE
trailer=# insert into harvester values (1,'grain'), (2,'cricket');
INSERT 0 2
trailer=# create table donkey (id int, others int references
harvester(id));
CREATE TABLE
trailer=# create unique index donkey_ears on donkey (id, others);
CREATE INDEX
trailer=# create view combine as select id, array_agg(others) as others
from donkey group by id;
CREATE VIEW
trailer=# create rule combine_insert as on insert to combine do instead
(delete from donkey where donkey.id=new.id;insert into donkey select
new.id,unnest(new.others) );
CREATE RULE
trailer=# insert into combine values (1,'{1,2}');INSERT 0 2
trailer=# select * from combine ;
id | others 
----+--------
  1 | {1,2}
(1 row)

trailer=# insert into combine values (1,'{1,2}');
INSERT 0 2
trailer=# select * from combine ;
 id | others 
----+--------
  1 | {1,2}
    (1 row)

trailer=# insert into combine values (2,'{1,2,3}');
ERROR:  insert or update on table "donkey" violates foreign key
constraint "donkey_others_fkey"
DETAIL:  Key (others)=(3) is not present in table "harvester".
trailer=# 

それがお役に立てば幸いです。要件に応じて、もう少し効率化してルールを追加できます。


1

ここでその機能を許可するパッチを取得したら

ただ使用する: ELEMENT REFERENCES relation( field )

インスタンス:

CREATE TABLE drivers (
   driver_id integer PRIMARY KEY,
   first_name text,
   last_name text,
   ...
);



CREATE TABLE races (
   race_id integer PRIMARY KEY,
   title text,
   race_day DATE,
   ...
   practice1_positions integer[] ELEMENT REFERENCES drivers,
   practice2_positions integer[] ELEMENT REFERENCES drivers,
   practice3_positions integer[] ELEMENT REFERENCES drivers,
   qualifying_positions integer[] ELEMENT REFERENCES drivers,
   final_positions integer[] ELEMENT REFERENCES drivers
);

1
それは素晴らしいアイデアのように見えるが、それは手動でパッチを適用せずにエンジンを使用することはできません-これはダウン票の理由です...
langpavel
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.