假设有两个表
1.student(roll_no, class, credits)
2.class(class, total_student, Total_credits)
如何使用学生表上的光标创建触发器更新课程 学生总数和他们的总学分? 每次插入或删除
答案 0 :(得分:1)
更新total_student
表的total_credit
和class
列将涉及在student
表上定义的触发器中针对student
表编写查询。这样做会导致 ORA-04091:表名发生变异,触发/功能可能看不到错误。为了避免该错误,每次{{1}中的某些内容发生变化(删除/插入/更新)时,至少有三种方法可以使total_student
和total_credits
更新 }表。假设主表(student
)/详细(class
)关系中的表:
第一种方法(最大的方法)将涉及创建多个数据库对象:
嵌套表SQL类型
student
包含该SQL类型的变量以存储类create or replace type T_clasids is table of number;
的包。以某种方式受到DML声明的影响。
包装规格:
ID
包体:
create or replace package Pkg
is
procedure reset_list_of_ids; -- empties out the list of class ids
procedure add_id(p_id in number); -- add new class id to a list if row
-- with this ID has been affected by
-- a DML statement
procedure update_class; -- updates class table
end;
端;
三个触发器:a)声明之前; b)排后; c)声明后。
create or replace package body PKG
is
g_classids T_clasids := T_clasids();
procedure reset_list_of_ids
is
begin
g_classids.delete;
end;
procedure add_id(p_id in number)
is
begin
g_classids.extend;
g_classids(g_classids.count) := p_id;
end;
procedure update_class
is
begin
update class t
set ( t.total_student
, t.total_credits ) = ( select count(*)
, sum(s.credits)
from student s
where s.class = t.class)
where t.class in (select column_value
from table(g_classids));
end;
以下是其工作原理的示例:
-- before insert/update/delete statement level trigger
-- to empty out the class id list
create or replace trigger tr_bs_initialize
before insert or delete or update on student
begin
pkg.reset_list_of_ids;
end;
-- after insert/update/delete statement level trigger
-- to update class table with new information
create or replace trigger tr_as_update_class
after insert or delete or update on student
begin
pkg.update_class;
end;
-- after insert/update/delete row level trigger
-- to populate class id collection with ids of
-- rows which has been affected by a DML statement
create or replace trigger tr_ar_populate
after insert or delete or update on student
for each row
begin
-- nvl(:new.class, :old.class)
-- in a case :new.clas happens to be null
pkg.add_id(nvl(:new.class, :old.class));
end;
第二种方法(最短的一种,个人更喜欢的方法)是从select t.* from class t;
CLASS TOTAL_STUDENT TOTAL_CREDITS
---------- ------------- -------------
1 null null
2 null null
3 null null
insert into student(roll_no, class, credits)
values(1, 2, 3);
select t.* from class t;
CLASS TOTAL_STUDENT TOTAL_CREDITS
---------- ------------- -------------
1 null null
2 1 3
3 null null
表中删除total_student
和total_credits
,创建一个能够计算并保持最新的视图关于班级学生总人数和学分总和的信息:
class
第三种方法。在 create or replace view v_class as
select c.class
, count(s.class) as total_students
, sum(s.credits) as total_credits
from student s
right join class c
on (c.class = s.class)
group by c.class
select t.* from v_class t;
CLASS TOTAL_STUDENTS TOTAL_CREDITS
---------- ------------- -------------
1 null null
2 1 3
3 null null
表上插入/更新/删除语句级别触发器后定义一个,并使用sudent
语句更新merge
表:
class
Find out more关于 create or replace trigger tr_aiudsl
after insert or update or delete on student
begin
merge into class c
using (select t.class
, count(*) as total_students
, sum(t.credits)as total_credit
from student t
group by t.class) q
on (q.class = c.class)
when matched
then update
set c.total_student = q.total_students
, c.total_credits = q.total_credit;
end;
声明。