0

我在执行触发器时遇到了麻烦。假设我有两种类型:

CREATE TYPE customer_t AS OBJECT( 
code INTEGER,
name VARCHAR(20),
surname VARCHAR(20),
age INTEGER);

和类型

CREATE TYPE ticket_t AS OBJECT (
price INTEGER,
cust REF customer_t
)

然后我有关联表:

CREATE TABLE customers OF TYPE customer_t

CREATE TABLE tickets OF TYPE ticket_t

我必须做一个练习,所以我必须创建一个触发器以确保客户不会购买超过 10 张门票,但是,如果我使用“select count(*)”之类的命令,我会收到一个错误,因为我无法访问到变异表。

请问有人可以帮我解决这个问题吗?

编辑:

我填充表格如下:

INSERT INTO custs (code, name, surname, age) values (123, 'Paolo', 'Past', 32);

并重复以下操作十次:

INSERT INTO tickets (price, cust) values 
(4, (SELECT * FROM (SELECT REF(T) FROM custs T WHERE name = 'Paolo' AND surname = 'Past') WHERE rownum < 2))

实现的触发器是:

create or replace
trigger check_num_ticket after insert on tickets
for each row
declare 
   num_ticket number;
begin
SELECT count(*) INTO num_ticket FROM tickets WHERE :new.cust = cust;
if (num_ticket >= 10) then
  raise_application_error('-20099', 'no ticket available');
end if;
end;

我得到这个错误:

A trigger (or a user defined plsql function that is referenced in
this statement) attempted to look at (or modify) a table that was
in the middle of being modified by the statement which fired it.
4

1 回答 1

0

您收到变异表错误,因为您正在插入要获取行数的同一个表中。想象一下您的插入语句插入了两行。没有规则首先插入哪一行,最后插入哪一行,但是您的触发器会在插入的一行上触发,并且想知道表中已经有多少行。DBMS 告诉您这是未定义的,因为该表当前正在发生变化。

您需要一个后语句触发器而不是前行触发器。因此,当插入语句的插入完成时,您查看表以查看是否突然出现了行数过多的客户。

(一个很好的替代方案是复合触发器。它结合了行和语句触发器。因此,在行后部分中,您会记住某个数组/集合中的客户,而在后语句部分中,您将只查找表中记住的顾客。)

于 2019-02-01T20:39:42.227 回答