就个人而言,我会添加一个AIRCRAFT 和一个SEAT 表:
CREATE TABLE aircraft (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT aircraft__id__pk PRIMARY KEY,
tail_number VARCHAR2(6)
NOT NULL
CONSTRAINT aircraft__tn__u UNIQUE
CONSTRAINT aircraft__tn_chk CHECK(
REGEXP_LIKE(
tail_number,
'[A-Z]\d{1,5}|[A-Z]\d{1,4}[A-Z]|[A-Z]\d{1,3}[A-Z]{2}'
)
),
manufacturer VARCHAR2(20)
NOT NULL,
model VARCHAR2(20)
NOT NULL,
airline_id CONSTRAINT aircraft__aid__fk REFERENCES airline(airline_id)
NOT NULL
);
CREATE TABLE seat (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT seat__id__pk PRIMARY KEY,
aircraft_id CONSTRAINT seat__aid__fk REFERENCES aircraft(id)
NOT NULL,
seat_row VARCHAR2(3)
NOT NULL,
seat_column NUMBER
NOT NULL,
CONSTRAINT seat__aid_r_c__u UNIQUE (aircraft_id, seat_row, seat_column)
);
那么您的flight 表将引用aircraft:
CREATE TABLE flight (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT flight__id__pk PRIMARY KEY,
aircraft_id CONSTRAINT flight__aid__fk REFERENCES aircraft(id)
NOT NULL
-- ...
);
而ticket 将引用flight 和seat:
CREATE TABLE ticket (
id NUMBER
GENERATED ALWAYS AS IDENTITY
CONSTRAINT ticket__id__pk PRIMARY KEY,
flight_id CONSTRAINT ticket__fid__fk REFERENCES flight(id)
NOT NULL,
seat_id CONSTRAINT ticket__sid__fk REFERENCES seat(id)
NOT NULL,
-- ...
CONSTRAINT ticket__fid_sid__u UNIQUE (flight_id, seat_id)
);
那么您永远不能出售 aircraft 上不存在的 seat 并且不需要计算最大门票数量并将其与座位进行比较(并且 seat 已添加属性,例如其位置可以显示在机票上的飞机)。
然后,您需要确保引用一致性,对于ticket,flight 和seat 在同一个aircraft 上;这可以通过触发器来完成:
CREATE TRIGGER ticket_check_seat_on_flight
BEFORE INSERT OR UPDATE ON ticket
FOR EACH ROW
DECLARE
is_valid NUMBER(1);
BEGIN
SELECT 1
INTO is_valid
FROM flight f
INNER JOIN seat s
ON (f.aircraft_id = s.aircraft_id)
WHERE f.id = :NEW.flight_id
AND s.id = :NEW.seat_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(
-20000,
'Flight and seat are on different aircraft.'
);
END;
/
db小提琴here