ジョブの役割を含むテーブルがあるとします。
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[]
の各メンバーに対する外部キー制約で、roles.roleを参照する場合のようです。
これはpostgresでは不可能のようです。私はこれを間違った方法で見ていますか?これを処理するための推奨される「正しい」方法は何ですか?
配列の外部キーのサポートは、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
に配置するだけです。
私は同僚のために似たようなものを作りました。基本的に、適切な制約を使用して(ユーザー、ロール)のペアごとに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=#
お役に立てば幸いです。これをもう少し効率的にして、要件に応じてルールを追加できます。
その機能を可能にするパッチを入手したら 詳細はこちら
ただ使用してください: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
);