Dizi üyesinde yabancı anahtar kısıtlaması?


27

İş rollerini içeren bir masam olduğunu varsayalım:

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

Diyelim ki bir tablom var, kullanıcılar ve her satırda (belirli bir kullanıcı) rasgele sayıda iş rolü olabilir:

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

Muhtemelen her üyenin users.roles[]roles.role'da olduğundan emin olmalıyım. Bana öyle geliyor ki, istediğim şey, her bir users.roles[]üyede yabancı bir anahtar kısıtlama olması.

Bu postgres ile mümkün görünmüyor. Buna yanlış mı bakıyorum? Bunu yapmanın önerilen "doğru" yolu nedir?

Yanıtlar:


20

Dizi yabancı anahtarlar için destek PostgreSQL 9.3'e girme hedefiyle gerçekleştirildi, ancak performans ve güvenilirlik sorunları nedeniyle sürümde kesinti yapılmadı. 9.4 için çalışılıyor gibi görünmüyor.

Şu anda, bir m: n ilişkisini modellemek için bir "birleştirme tablosu" kullanmanın olağan ilişkisel yaklaşımına bağlı kalmanız gerekir.

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

Kullanıcı adlarını / rol adlarını doğrudan birleştirme tablosuna kaydetmek yerine, bu durumda vekil anahtarların kullanılmasını da öneririm . Bir kullanıcıyı veya rolü ilk kez yeniden adlandırmak istediğinizde, vekil tuşlarını kullandığınız için mutlu olursunuz. Sadece ve uniqueüzerine bir kısıtlama koyun .roles."role"users.username


3

Bir meslektaşım için benzer bir şey yaptım. Temel olarak, her bir (kullanıcı, rol) çifti için uygun kısıtlamaları olan bir satır içeren gizli bir tablo hazırladım. Kullanıcı tablosu daha sonra, tüm roller bir diziye monte edilmiş olarak saklanan tablonun bir görünümüydü. Daha sonra uygun bir kural ekleyerek görünüme eklemeyi mümkün hale getirdim. İşte nasıl:

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

Umarım bu yardımcı olur. Biraz daha verimli hale getirebilir ve gereksinimlerinize bağlı olarak daha fazla kural ekleyebilirsiniz.


1

Bir kez daha bu işlevselliği sağlayan yamayı alınca burada

Sadece kullan: ELEMENT REFERENCES relation( field )

İntance için:

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
Harika bir fikir gibi gözüküyor, ancak motoru manuel olarak yamalamadan kullanılamaz - bu aşağı oylamaların nedeni…
langpavel
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.