【问题标题】:Oracle and mutating table with simple exercise简单练习的 Oracle 和变异表
【发布时间】:2019-06-26 10:56:18
【问题描述】:

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

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.

【问题讨论】:

  • 你能告诉我们你的触发器代码和你得到的错误吗?
  • @GMB 我编辑了帖子
  • 这个网站已经有很多关于变异表错误的问题。 Why not check out some of them?

标签: sql oracle oracle11g database-trigger mutating-table


【解决方案1】:

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

您需要一个后语句触发器而不是前行触发器。所以当insert语句的insert完成后,你看一下表,看看是不是突然出现了太多行的客户。

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

【讨论】:

  • 因此,如果您查看编辑,我必须创建一个 after 语句触发器。但我必须检查什么?在那种情况下,我没有 :new 变量
  • 我会说类似于SELECT cust BULK COLLECT INTO array_cutomers FROM tickets GROUP BY cust HAVING COUNT(*) &gt; 10;IF array_cutomers.COUNT &gt; 0 THEN ...。或SELECT count(*) INTO num_customers FROM (SELECT cust FROM tickets GROUP BY cust HAVING COUNT(*) &gt; 10);IF num_customers &gt; 0 THEN ...。如前所述,使用复合触发器,您甚至可以收集所有要检查的客户,而不是检查整个表格。
  • 如何实现复合触发器?我从来没有研究过这种东西
  • 一步一步学习。从 after 语句触发器开始。成功完成此操作后,请在 Google 上搜索有关复合触发器的示例,看看它们是如何工作的。
  • @Paolopast,您可以查看此内容以供参考:livesql.oracle.com/apex/livesql/file/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-24
  • 1970-01-01
  • 2013-02-08
  • 1970-01-01
相关资源
最近更新 更多