배열 멤버에 외래 키 제약 조건이 있습니까?


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에 대해서는 작동하지 않는 것 같습니다.

이때 "join table"을 사용하여 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

해당 기능을 더 많이 제공하는 패치를 받으면

그냥 사용하십시오 : 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.