Hạn chế khóa ngoại trên thành viên mảng?


27

Giả sử tôi có một bảng chứa các vai trò công việc:

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

Giả sử tôi có thêm một bảng, người dùng và mỗi hàng (một người dùng cụ thể) có thể có số lượng vai trò công việc tùy ý:

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

Tôi có lẽ nên đảm bảo rằng mỗi thành viên users.roles[]tồn tại trong vai trò.role. Dường như với tôi rằng những gì tôi muốn là một ràng buộc khóa ngoại đối với mỗi thành viên users.roles[]như vậy nếu tham chiếu vai trò.role.

Điều này dường như không thể với postgres. Tôi đang nhìn điều này sai cách? Cách "đúng" được đề xuất để xử lý việc này là gì?

Câu trả lời:


20

Hỗ trợ cho các khóa ngoại mảng đã được thực hiện với mục tiêu đưa nó vào PostgreQuery 9.3, nhưng nó đã không thực hiện việc cắt giảm để phát hành do các vấn đề về hiệu suất và độ tin cậy. Nó dường như không được làm việc trong 9,4.

Tại thời điểm này, bạn cần tuân theo cách tiếp cận quan hệ thông thường là sử dụng "bảng tham gia" để mô hình hóa mối quan hệ m: n.

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

Tôi cũng đề nghị sử dụng các khóa thay thế trong trường hợp này, thay vì lưu trữ tên người dùng / tên vai trò trực tiếp trong bảng tham gia. Lần đầu tiên bạn muốn đổi tên người dùng hoặc vai trò, bạn sẽ rất vui khi bạn sử dụng các khóa thay thế. Chỉ cần đặt một uniqueràng buộc trên roles."role"users.username.


3

Tôi chỉ làm một cái gì đó tương tự cho một đồng nghiệp. Về cơ bản, tôi đã tạo một bảng ẩn chứa một hàng cho mỗi cặp (người dùng, vai trò) với các ràng buộc phù hợp. Bảng người dùng sau đó là một khung nhìn của bảng ẩn với tất cả các vai trò được tập hợp thành một mảng. Sau đó tôi đã có thể chèn vào chế độ xem bằng cách thêm một quy tắc thích hợp. Đây là cách thực hiện:

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

Tôi hy vọng điều đó sẽ giúp. Bạn có thể làm cho nó hiệu quả hơn một chút và thêm nhiều quy tắc tùy theo yêu cầu của bạn.


1

Khi bạn nhận được bản vá cho phép chức năng đó nhiều hơn ở đây

Chỉ dùng: ELEMENT REFERENCES relation( field )

Đối với ý định:

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
Có vẻ như đó là ý tưởng tuyệt vời nhưng nó không thể được sử dụng mà không có công cụ vá thủ công - đây là lý do khiến phiếu bầu giảm
langpavel
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.