如何在PostgreSQL中实现这种关系?
我需要每次会议至少有一个会话,但我不知道如何实现它。
这是我的尝试:
CREATE TABLE Meeting(
MeetingId INT PRIMARY KEY NOT NULL,
Cost INT NOT NULL,
StartDate DATE NOT NULL,
EndDate DATE NOT NULL
);
CREATE TABLE Session(
SessId INT PRIMARY KEY NOT NULL,
StartDate DATE NOT NULL,
EndDate DATE NOT NULL,
MeetingId INT NOT NULL REFERENCES Meeting(MeetingId) ON UPDATE CASCADE ON DELETE CASCADE
);
我应该添加一些新表或约束吗?
这似乎是先有鸡还是先有蛋的问题,但有一个(大部分)简单的解决方案可以完美运行:
CREATE TABLE meeting (
meeting_id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
, first_session_id int NOT NULL
, cost int NOT NULL
, startdate date NOT NULL
, enddate date NOT NULL
, CONSTRAINT session_meeting_id_fkey
FOREIGN KEY (meeting_id) REFERENCES meeting ON UPDATE CASCADE ON DELETE CASCADE
);
CREATE TABLE session (
session_id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY
, meeting_id int NOT NULL
, startdate date NOT NULL
, enddate date NOT NULL
, CONSTRAINT session_meeting_id_fkey
FOREIGN KEY (meeting_id) REFERENCES meeting ON UPDATE CASCADE ON DELETE CASCADE
, UNIQUE (meeting_id, session_id) -- needed for FK meeting_first_session_id_fkey
);
ALTER TABLE meeting ADD CONSTRAINT meeting_first_session_id_fkey
FOREIGN KEY (meeting_id, first_session_id) REFERENCES session(meeting_id, session_id); -- no cascading
现在,在不插入会话的情况下无法插入会议。并且始终强制执行参照完整性。
为了避免另一个潜伏的先有鸡还是先有蛋的问题,使用数据修改 CTE 插入会议 和 它的第一个会话:
WITH ins_meeting AS (
INSERT INTO meeting
(first_session_id , cost, startdate , enddate)
VALUES (nextval(pg_get_serial_sequence('session', 'session_id')), 1 , '2023-03-08', '2023-03-09')
RETURNING meeting_id, first_session_id
)
INSERT INTO session (session_id, meeting_id, startdate, enddate)
SELECT first_session_id, meeting_id, '2023-03-08', '2023-03-09'
FROM ins_meeting;
这是根据之前的回答优化的:
关于展示的
IDENTITY
专栏:
注意
nextval(pg_get_serial_sequence('session', 'session_id'))
的用法。参见:
A
PRIMARY KEY
列是隐式的 NOT NULL
。拼写出来是可选的噪音。参见: