bagaimana cara menggunakan pemicu dan kursor yang dikombinasikan dengan for loop di Oracle?

dengan asumsi dua meja

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

bagaimana cara membuat pemicu menggunakan kursor pada tabel siswa yang akan memperbarui kelas dengan Jumlah total Siswa dan total kredit mereka? pada setiap penyisipan atau penghapusan


person Community    schedule 02.09.2013    source sumber
comment
Adakah alasan khusus mengapa Anda ingin menggunakan pemicu untuk mendapatkan total siswa dan total kredit?   -  person Jacob    schedule 02.09.2013
comment
Sudahkah Anda mencoba membuatnya? Jika ya, apa yang tidak berhasil?   -  person DCookie    schedule 02.09.2013
comment
Coba lihat ini, mungkin bisa membantu. stackoverflow.com/questions/11580177/cursor-in-a-trigger   -  person Jacob    schedule 02.09.2013


Jawaban (1)


Memperbarui kolom total_student dan total_credit pada tabel class akan melibatkan penulisan kueri terhadap tabel student dalam pemicu yang ditentukan pada tabel student. Melakukan hal ini akan menyebabkan kesalahan ORA-04091: nama tabel bermutasi, pemicu/fungsi mungkin tidak melihatnya. Untuk menghindari kesalahan itu setidaknya ada tiga pendekatan untuk mendapatkan total_student dan total_credits diperbarui setiap kali ada sesuatu yang berubah (hapus/masukkan/perbarui) di tabel student. Asumsi telah dibuat bahwa tabel dalam hubungan master(class)/detail(student) :

  1. Pendekatan pertama (yang terbesar) akan melibatkan pembuatan beberapa objek database:

    1. Tipe SQL tabel bersarang

      create or replace type T_clasids is table of number;
      
    2. Paket yang akan memiliki variabel tipe SQL untuk menyimpan kelas IDs. yang entah bagaimana telah dipengaruhi oleh pernyataan DML.

      Spesifikasi paket:

      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;
      

      Badan paket:

      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;
      

      akhir;

    3. Tiga pemicu: a) Pernyataan sebelum; b) setelah baris; c) setelah pernyataan.

      -- 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;
      

      Berikut ini contoh cara kerjanya:

      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
      
  2. Pendekatan kedua (yang terpendek dan lebih disukai secara pribadi) adalah menghapus total_student dan total_credits dari tabel class, membuat tampilan yang akan menghitung dan menyimpan informasi terkini tentang jumlah total siswa di kelas dan jumlah kredit mereka:

        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
    
  3. Pendekatan ketiga. Tentukan satu setelah masukkan/perbarui/hapus pemicu tingkat pernyataan pada tabel sudent dan gunakan pernyataan merge untuk memperbarui tabel class:

         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;
    

    Cari tahu lebih lanjut tentang pernyataan merge.

person Nick Krasnov    schedule 02.09.2013
comment
+Satu untuk penjelasan mendetail. Namun saya punya satu keraguan, pendekatan ketiga tidak memunculkan pemicu mutasi atau jika penggabungan digunakan, pemicu mutasi dapat dihindari? - person Jacob; 03.09.2013
comment
@Polppan Dalam pendekatan ketiga kami menggunakan pemicu level setelah pernyataan (bukan baris). Pemicu semacam itu tidak menimbulkan kesalahan mutasi tabel - data diakses pada saat data sudah diubah - person Nick Krasnov; 03.09.2013
comment
Pendekatan ke-3 lebih disukai oleh guru kami, namun kami hanya harus menggunakan kursor dan tampilan pemicu tidak diperbolehkan dalam tugas ini. tapi terima kasih, ini penjelasan yang sangat singkat untuk saya dan teman-teman :) - person ; 04.09.2013