如何在oracle中结合for循环使用触发器和游标?

时间:2013-09-02 17:41:56

标签: sql oracle triggers

假设有两个表

 1.student(roll_no, class, credits)
 2.class(class, total_student, Total_credits)

如何使用学生表上的光标创建触发器更新课程 学生总数他们的总学分? 每次插入或删除

1 个答案:

答案 0 :(得分:1)

更新total_student表的total_creditclass列将涉及在student表上定义的触发器中针对student表编写查询。这样做会导致 ORA-04091:表名发生变异,触发/功能可能看不到错误。为了避免该错误,每次{{1}中的某些内容发生变化(删除/插入/更新)时,至少有三种方法可以使total_studenttotal_credits 更新 }表。假设主表(student)/详细(class)关系中的表:

  1. 第一种方法(最大的方法)将涉及创建多个数据库对象:

    1. 嵌套表SQL类型

      student
    2. 包含该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;
      

      端;

    3. 三个触发器: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;
      
  2. 第二种方法(最短的一种,个人更喜欢的方法)是从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_studenttotal_credits,创建一个能够计算并保持最新的视图关于班级学生总人数和学分总和的信息:

    class
  3. 第三种方法。在 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; 声明。