ali*_*noi 4 postgresql database-design constraint
考虑以下业务领域:
Airline具有唯一的航空公司 ID ( aid) 并包含零个或多个Planes。Plane有一个唯一的飞机 id ( pid) Airline(但来自不同国家的飞机Airlines可以有重叠ids)。Plane都有一个或多个Seats。Seat有一个唯一的座位 id ( sid) (但Seats不同的座位 idPlanes可能有重叠ids)。这是我解决这个问题的尝试:
CREATE SEQUENCE planes_seq;
CREATE TABLE Airlines (
aid INTEGER PRIMARY KEY DEFAULT nextval('planes_seq')
);
CREATE TABLE Planes (
aid INTEGER REFERENCES Airlines(aid)
, pid INTEGER
, PRIMARY KEY(aid, pid)
);
CREATE TABLE Seats (
aid INTEGER
, pid INTEGER
, sid INTEGER
, PRIMARY KEY(aid, pid, sid)
, FOREIGN KEY(aid, pid) REFERENCES Planes(aid, pid)
);
ALTER TABLE Planes ADD CONSTRAINT fk_seats FOREIGN KEY(aid, pid)
REFERENCES Seats(aid, pid);
Run Code Online (Sandbox Code Playgroud)
然而,它失败了,因为决赛ALTER TABLE是非法的,因为这对(Seats.aid, Seats.pid)确实不是唯一的。
PS:我是 SQL 新手,这是家庭作业的(一小部分)。我尝试遵循另一个 DBA 问题中的父级至少一个子级示例(约束在数据库中强制执行“至少一个”或“恰好一个”),但是那里有太多我无法做到的技巧理解(多个WITH查询、一个RETURNING子句等)。在我看来,必须有一种更简单的方法来做到这一点。
CTE (WITH和RETURNING) 的存在是为了避免使用延迟约束。
从概念上讲,使用延迟约束更简单,对于家庭作业,我建议您首先使用它们。例如,与您的注释不同的地方:
CREATE SEQUENCE planes_seq;
CREATE TABLE airlines (
aid INTEGER PRIMARY KEY DEFAULT nextval('planes_seq')
);
CREATE TABLE planes (
aid INTEGER NOT NULL REFERENCES airlines (aid)
, pid INTEGER NOT NULL
, sid INTEGER NOT NULL -- we add a default seat
DEFAULT 1 CHECK (sid = 1) -- in every plane
, PRIMARY KEY (aid, pid)
);
CREATE TABLE seats (
aid INTEGER NOT NULL
, pid INTEGER NOT NULL
, sid INTEGER NOT NULL
, PRIMARY KEY (aid, pid, sid)
, FOREIGN KEY (aid, pid) REFERENCES planes (aid, pid)
);
ALTER TABLE planes ADD CONSTRAINT fk_seats
FOREIGN KEY (aid, pid, sid)
REFERENCES seats (aid, pid, sid)
DEFERRABLE INITIALLY DEFERRED ; -- the DEFERRABLE is important
Run Code Online (Sandbox Code Playgroud)
现在我们可以添加一些数据:
INSERT INTO airlines (aid)
VALUES (1) ; -- our 1st airline
BEGIN ;
INSERT INTO planes -- its 1st plane
(aid, pid) -- notice: sid is added by default as 1
VALUES
(1, 1) ;
INSERT INTO seats
(aid, pid, sid)
VALUES -- 3 seats in the 1st plane
(1, 1, 1),
(1, 1, 2),
(1, 1, 3) ;
COMMIT ;
Run Code Online (Sandbox Code Playgroud)
我们需要在事务中插入新飞机(及其座位),否则会失败。
DEFERRABLE意味着我们可以“推迟”对FOREIGN KEY约束的检查,直到事务结束(在插入/更新/删除语句之后立即检查不是推迟的约束。)如果您尝试仅在平面中插入,它将失败。
INITIALLY DEFERRED意味着我们希望在外键约束创建后立即“推迟”它。这本来可以稍后完成(您可以设置和取消设置延迟约束,如果它们已定义为DEFERRABLE)。
| 归档时间: |
|
| 查看次数: |
853 次 |
| 最近记录: |