Vincolo di chiave esterna sul membro dell'array?


27

Supponiamo di avere una tabella contenente ruoli di lavoro:

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

Supponiamo che io abbia una tabella, gli utenti e ogni riga (un utente specifico) può avere un numero arbitrario di ruoli lavorativi:

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

Probabilmente dovrei assicurarmi che ogni membro di users.roles[]esiste in role.role. Mi sembra che ciò che voglio sia un vincolo di chiave esterna su ogni membro di users.roles[]tale che se fa riferimento a ruoli.role.

Questo non sembra possibile con Postgres. Sto guardando questo nel modo sbagliato? Qual è il modo "giusto" suggerito per gestirlo?

Risposte:


20

Il supporto per le chiavi esterne dell'array è stato elaborato con l'obiettivo di inserirlo in PostgreSQL 9.3, ma non ha fatto il taglio per il rilascio a causa di problemi di prestazioni e affidabilità. Non sembra essere stato lavorato su per 9.4.

In questo momento, è necessario attenersi al solito approccio relazionale dell'utilizzo di una "tabella di join" per modellare una relazione m: n.

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

Suggerisco di usare anche le chiavi surrogate in questo caso, piuttosto che memorizzare i nomi utente / i nomi dei ruoli direttamente nella tabella di join. La prima volta che vuoi rinominare un utente o un ruolo, sarai felice di aver usato le chiavi surrogate. Basta porre un uniquevincolo su roles."role"e users.username.


3

Ho appena fatto qualcosa di simile per un collega. In sostanza ho creato una tabella nascosta che conteneva una riga per ogni coppia (utente, ruolo) con vincoli adeguati. La tabella utente era quindi una vista della tabella nascosta con tutti i ruoli assemblati in un array. Ho quindi reso possibile l'inserimento nella vista aggiungendo una regola appropriata. Ecco come:

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

Spero che aiuti. Puoi renderlo un po 'più efficiente e aggiungere più regole a seconda delle tue esigenze.


1

Una volta ottenuta la patch che consente tale funzionalità in più qui

Usa solo: ELEMENT REFERENCES relation( field )

Per 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
Sembra un'ottima idea ma non può essere utilizzato senza il patching manuale del motore - questo è il motivo dei voti
negativi
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.