如何在一对多关系中强制执行“至少一个”?

问题描述 投票:0回答:1

如何在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
);

我应该添加一些新表或约束吗?

sql postgresql database-design foreign-keys data-modeling
1个回答
0
投票

这似乎是先有鸡还是先有蛋的问题,但有一个(大部分)简单的解决方案可以完美运行:

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
。拼写出来是可选的噪音。参见:

© www.soinside.com 2019 - 2024. All rights reserved.