Mengapa saya TIDAK mendapatkan kesalahan tabel mutasi di pemicu?

11

Ini (atau setidaknya diketahui) bahwa Anda tidak dapat menggunakan pernyataan DML pada tabel bermutasi di dalam pemicu. Kutipan dari dokumentasi Oracle :

Tabel mutasi adalah tabel yang sedang dimodifikasi oleh pernyataan UPDATE, DELETE, atau INSERT, atau tabel yang mungkin diperbarui oleh efek dari batasan DELETE CASCADE.

Sesi yang mengeluarkan pernyataan pemicu tidak dapat meminta atau mengubah tabel mutasi. Pembatasan ini mencegah pemicu dari melihat set data yang tidak konsisten.

Namun, saya tidak bisa mengerti mengapa pemicu demo ini tidak gagal dengan kesalahan "tabel mutasi" ketika saya melakukan insert into empmenggunakan SQL Developer atau SQL * Plus:

CREATE OR REPLACE TRIGGER emp_bri   
  BEFORE INSERT ON emp 
    FOR EACH ROW
BEGIN

  SELECT max(id) + 1 INTO :NEW.id FROM emp;
  UPDATE emp SET salary = 5000;

END emp_bri;

Penyisipan berhasil diselesaikan dengan nilai berikutnya iddan memperbarui semua empcatatan. Saya menggunakan Oracle Database 11g Enterprise Edition Release 11.2.0.1.0. Saya telah membaca tentang pemicu senyawa tetapi sampel tidak menggunakannya.

Centurion
sumber
1
Tidak terkait dengan pertanyaan Anda, tetapi: JANGAN gunakan select max(id)untuk menetapkan nomor unik. Hanya saja, jangan. Itu hanya salah dan tidak akan skala juga.
a_horse_with_no_name
Ya, saya tahu itu :) Contohnya mungkin tidak terlalu baik dalam hal ini ... Nilai peningkatan otomatis harus diterapkan dengan menggunakan urutan dan pemicu.
Centurion
Ini memang aneh. Btw: di sini adalah contoh SQLFiddle sqlfiddle.com/#!4/9e59f/2
a_horse_with_no_name
Terima kasih telah berbagi info, tautan keren. Tidak tahu ada situs pengujian Oracle SQL seperti itu :)
Centurion
a_horse_with_no_name: Contoh lain: Fiddle-test-2 (SET gaji = gaji + 10)
ypercubeᵀᴹ

Jawaban:

12

Ada pengecualian. Saat Anda menentukan before insertpemicu, tingkat baris pada tabel dan mengeluarkan INSERTpernyataan baris tunggal , table is mutatingkesalahan tidak akan dinaikkan. Tetapi jika Anda mendefinisikan jenis pemicu yang sama dan mengeluarkan pernyataan multi-baris INSERT, kesalahan akan dimunculkan. Berikut ini sebuah contoh:

SQL> create table TB_TR_TEST(
  2    col1 number,
  3    col2 number
  4  )
  5  ;

Table created

SQL> create or replace trigger TR_TB_TR_TEST
  2  before insert on TB_TR_TEST
  3  for each row
  4  begin
  5    SELECT max(col1) + 1 INTO :NEW.col1
  6      FROM TB_TR_TEST;
  7    UPDATE TB_TR_TEST SET col2 = 5000;
  8  end;
  9  /

Trigger created

Berikut ini adalah insertpernyataan baris tunggal , yang tidak akan meningkatkan kesalahan tabel mutasi:

SQL> insert into TB_TR_TEST(col1, col2) values(1,2);

1 row inserted

SQL> insert into TB_TR_TEST(col1, col2) values(3,5);

1 row inserted

SQL> commit;

Commit complete

Berikut ini adalah pernyataan penyisipan multi-baris, yang akan memunculkan kesalahan tabel mutasi:

SQL> insert into TB_TR_TEST(col1, col2)
  2    select 1, 2
  3      from dual;

insert into TB_TR_TEST(col1, col2)
  select 1, 2
    from dual

ORA-04091: table HR.TB_TR_TEST is mutating, trigger/function may not see it
ORA-06512: at "HR.TR_TB_TR_TEST", line 2
ORA-04088: error during execution of trigger 'HR.TR_TB_TR_TEST'
Nicholas Krasnov
sumber
Tampaknya memang itulah penyebabnya. Apakah Anda memiliki referensi dalam manual untuk perilaku ini?
a_horse_with_no_name
@a_horse_with_no_name jika Anda memiliki akses ke support.oracle.com, cari ID 132569.1( ORA-4091 on BEFORE ROW TRIGGER with INSERT .. into SELECT statement).
Nicholas Krasnov
2
Terima kasih. Cukup menarik pengecualian ini tampaknya hanya didokumentasikan dalam manual 8i (!): Docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/… (bagian " " Tabel Bermutasi dan Pembatas ") Saya bisa ' t menemukan pernyataan itu dalam manual saat ini
a_horse_with_no_name