트리거 또는 PL / pgSQL이 전혀 필요하지 않습니다.
당신은 제약 이 필요 하지 않습니다 DEFERRABLE
.
또한 정보를 중복으로 저장할 필요가 없습니다.
users
표에 활성 이메일의 ID를 포함시켜 상호 참조하십시오. DEFERRABLE
사용자와 활성 전자 메일을 삽입하는 데 따른 치킨 앤에 그 문제를 해결하기 위해서는 제약이 필요하다고 생각할 수도 있지만 데이터 수정 CTE를 사용하면 그럴 필요조차 없습니다.
이렇게 하면 항상 사용자 당 하나의 활성 이메일이 항상 적용됩니다.
CREATE TABLE users (
user_id serial PRIMARY KEY
, username text NOT NULL
, email_id int NOT NULL -- FK to active email, constraint added below
);
CREATE TABLE email (
email_id serial PRIMARY KEY
, user_id int NOT NULL REFERENCES users ON DELETE CASCADE ON UPDATE CASCADE
, email text NOT NULL
, CONSTRAINT email_fk_uni UNIQUE(user_id, email_id) -- for FK constraint below
);
ALTER TABLE users ADD CONSTRAINT active_email_fkey
FOREIGN KEY (user_id, email_id) REFERENCES email(user_id, email_id);
NOT NULL
구속 조건을 제거하여 users.email_id
"최대 하나의 활성 이메일"로 만드십시오. (사용자 당 여러 개의 전자 메일을 계속 저장할 수 있지만 "활성"인 전자 메일은 없습니다.)
당신은 할 수 있도록 active_email_fkey
DEFERRABLE
합니다 (별도의 명령에 사용자와 이메일 삽입 더 여유있게 같은 거래),하지만 그건 필요가 없습니다 .
내가 넣어 user_id
먼저 UNIQUE
제약 조건 email_fk_uni
최적화 인덱스 범위에. 세부:
선택적보기 :
CREATE VIEW user_with_active_email AS
SELECT * FROM users JOIN email USING (user_id, email_id);
활성 이메일을 사용하여 새 사용자를 삽입하는 방법은 다음과 같습니다 (필요한 경우).
WITH new_data(username, email) AS (
VALUES
('usr1', 'abc@d.com') -- new users with *1* active email
, ('usr2', 'def3@d.com')
, ('usr3', 'ghi1@d.com')
)
, u AS (
INSERT INTO users(username, email_id)
SELECT n.username, nextval('email_email_id_seq'::regclass)
FROM new_data n
RETURNING *
)
INSERT INTO email(email_id, user_id, email)
SELECT u.email_id, u.user_id, n.email
FROM u
JOIN new_data n USING (username);
구체적인 어려움은 우리가 시작 user_id
하거나 email_id
시작 하지 않아도 된다는 것 입니다. 둘 다 각각의 일련 번호입니다 SEQUENCE
. 단일 RETURNING
조항 (또 다른 닭과 계란 문제) 으로 해결할 수 없습니다 . 용액은 nextval()
으로 아래 링크 대답 상세히 설명 .
열에 첨부 된 시퀀스의 이름을 모르는 경우 바꿀 수 있습니다.serial
email.email_id
nextval('email_email_id_seq'::regclass)
와
nextval(pg_get_serial_sequence('email', 'email_id'))
새로운 "활성"이메일을 추가하는 방법은 다음과 같습니다.
WITH e AS (
INSERT INTO email (user_id, email)
VALUES (3, 'new_active@d.com')
RETURNING *
)
UPDATE users u
SET email_id = e.email_id
FROM e
WHERE u.user_id = e.user_id;
SQL 바이올린.
간단한 ORM이 이것에 대처할만큼 똑똑하지 않은 경우 서버 측 함수에서 SQL 명령을 캡슐화 할 수 있습니다.
충분한 설명과 밀접한 관련이 있습니다.
또한 관련 :
DEFERRABLE
구속 조건 정보 :
소개 nextval()
및 pg_get_serial_sequence()
: