ข้อ จำกัด กุญแจต่างประเทศของสมาชิกอาเรย์?


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[]มีอยู่ใน role.role สำหรับฉันดูเหมือนว่าสิ่งที่ฉันต้องการคือข้อ จำกัด ที่สำคัญต่างประเทศของสมาชิกแต่ละคนของusers.roles[]สิ่งนั้นหากอ้างอิงถึง role.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

ฉันเพิ่งทำสิ่งที่คล้ายกันสำหรับเพื่อนร่วมงาน โดยพื้นฐานแล้วฉันสร้างตารางที่ซ่อนอยู่ซึ่งมีหนึ่งแถวสำหรับคู่ (ผู้ใช้บทบาท) ที่มีข้อ จำกัด ที่เหมาะสม จากนั้นตารางผู้ใช้จะเป็นมุมมองของตารางที่ซ่อนอยู่ซึ่งมีบทบาททั้งหมดรวมอยู่ในอาร์เรย์ ฉันทำให้มันเป็นไปได้ที่จะแทรกลงในมุมมองโดยการเพิ่มกฎที่เหมาะสม นี่คือวิธี:

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

เมื่อคุณได้รับ patch ที่ช่วยให้สามารถใช้งานได้มากขึ้นแล้ว

เพียงใช้: 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.