
我为航班设计了机票系统。我想增加一个约束,这样你可以插入的机票数量少于一架飞机的座位数。
假设我插入了一架有10个座位的飞机。我只能为那次航班插入10张机票。否则,应出现错误消息。
我试着在航班号上使用计数函数做一个触发器。
CREATE OR REPLACE TRIGGER trg_ticket_BRIU
BEFORE INSERT OR UPDATE ON Ticket
FOR EACH ROW
DECLARE
l_numberofseats flight.numberofseats%type;
BEGIN
select numberofseats into l_numberofseats
from flight
where flightnumber=:new.flightnumber;
IF :new.count(flightnumber) > l_numberofseats
THEN
raise_application_error(-2000, 'Not enough seats');
END IF;
END;但我知道这个错误
Trigger TRG_TICKET_BRIU compiled
LINE/COL ERROR
--------- -------------------------------------------------------------
8/5 PLS-00049: bad bind variable 'NEW.COUNT'
Errors: check compiler log发布于 2021-12-14 21:00:31
就我个人而言,我会添加一个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)
);然后,您就永远不能销售一个不存在于seat上的aircraft,并且不需要计算最大票数并将其与座位进行比较(而且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<>fiddle https://dbfiddle.uk/?rdbms=oracle_18&fiddle=659ec800cf3432343f0dc32082616be9
发布于 2021-12-14 21:20:20
您可以使用AFTER STATEMENT触发器:
CREATE TRIGGER ticket__check_number_of_seats
AFTER INSERT OR UPDATE OR DELETE ON ticket
DECLARE
is_invalid NUMBER(1,0);
BEGIN
SELECT 1
INTO is_invalid
FROM flight f
INNER JOIN (
SELECT flight_id,
COUNT(*) AS tickets_sold
FROM ticket
GROUP BY flight_id
) t
ON f.id = t.flight_id
WHERE t.tickets_sold > f.number_of_seats;
RAISE_APPLICATION_ERROR(
-20000,
'Too many tickets sold for flight.'
);
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
/通过使用复合触发器将每一行的flight_id值排序为集合,然后在语句之后只检查这些航班的机票数量,可以提高效率;但是,我将保留这个扩展作为OP的练习。
db<>fiddle https://dbfiddle.uk/?rdbms=oracle_18&fiddle=054f47db8dd219cc90873ba404c49d9d
发布于 2021-12-14 22:15:30
正如其他人所指出的,没有:new.count列。这是因为:new (and :old)创建一个伪行,其中包含与表定义完全相同的列。此外,您将从Mutating获得flight_number中需要计算的一个tickets异常。但是,因为这是导致he触发器触发的表,所以不能引用它。那么要做什么:创建一个复合触发器和一个支持类型(嵌套表)。在其中,使用after row部分来捕获已处理的flight_numbers。然后,在after statement部分,您可以选择每次航班的机票数量。如果计数>0,则引发异常。(见演示 )
create type flight_tickets_ntt
is table of integer;
create or replace trigger trg_ticket_ciu
for update or insert on tickets
compound trigger
l_flights flight_tickets_ntt := flight_tickets_ntt();
after each row is
begin
if :new.flight_number not member of l_flights then
l_flights.extend ;
l_flights(l_flights.count) := :new.flight_number;
end if;
end after each row;
after statement is
l_flight_cnt flight.flight_number%type;
begin
select count(*)
into l_flight_cnt
from flight f
where f.number_of_seats <
( select count(*)
from tickets t
where t.flight_number in
( select *
from table (l_flights)
)
);
if l_flight_cnt > 0 then
raise_application_error(-20000, 'Not enough seats');
end if;
end after statement;
end trg_ticket_ciu; 还有一个您需要处理的问题:如果更新更改了航班号,或者可能更改了航班的数据(缺少的列),会发生什么情况。
https://stackoverflow.com/questions/70354491
复制相似问题