it-swarm.com.de

Fremdschlüsseleinschränkung für Array-Mitglied?

Angenommen, ich habe eine Tabelle mit Jobrollen:

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

Angenommen, ich habe weiterhin eine Tabelle, Benutzer und jede Zeile (ein bestimmter Benutzer) kann eine beliebige Anzahl von Jobrollen haben:

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

Ich sollte wahrscheinlich sicherstellen, dass jedes Mitglied von users.roles[] In role.role existiert. Es scheint mir, dass ich eine Fremdschlüsseleinschränkung für jedes Mitglied von users.roles[] Wollen möchte, so dass, wenn auf role.role verwiesen wird.

Dies scheint mit Postgres nicht möglich zu sein. Betrachte ich das falsch? Was ist der vorgeschlagene "richtige" Weg, um damit umzugehen?

28
user2965107

Die Unterstützung für Array-Fremdschlüssel wurde mit dem Ziel bearbeitet, sie in PostgreSQL 9.3 zu integrieren, aber aufgrund von Leistungs- und Zuverlässigkeitsproblemen wurde die Veröffentlichung nicht gekürzt. Es scheint nicht für 9.4 gearbeitet zu werden.

Zu diesem Zeitpunkt müssen Sie sich an den üblichen relationalen Ansatz halten, eine "Join-Tabelle" zum Modellieren einer m: n-Beziehung zu verwenden.

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

Ich schlage vor, auch in diesem Fall Ersatzschlüssel zu verwenden, anstatt die Benutzernamen/Rollennamen direkt in der Join-Tabelle zu speichern. Wenn Sie zum ersten Mal einen Benutzer oder eine Rolle umbenennen möchten, sind Sie froh, dass Sie Ersatzschlüssel verwendet haben. Setzen Sie einfach eine unique Einschränkung auf roles."role" und users.username.

20
Craig Ringer

Ich habe gerade etwas Ähnliches für einen Kollegen gemacht. Im Wesentlichen habe ich eine versteckte Tabelle erstellt, die eine Zeile für jedes (Benutzer-, Rollen-) Paar mit geeigneten Einschränkungen enthielt. Die Benutzertabelle war dann eine Ansicht der verborgenen Tabelle mit allen Rollen, die zu einem Array zusammengefasst waren. Ich habe es dann möglich gemacht, in die Ansicht einzufügen, indem ich eine entsprechende Regel hinzugefügt habe. Hier ist, wie:

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=# 

Ich hoffe das hilft. Sie können es etwas effizienter gestalten und je nach Ihren Anforderungen weitere Regeln hinzufügen.

3
Max Murphy

Sobald Sie den Patch erhalten haben, der diese Funktionalität ermöglicht mehr hier

Verwenden Sie einfach: ELEMENT REFERENCES relation( field )

Zur Intance:

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
Ian Mbae