เหตุใดฉันจึงไม่ได้รับข้อผิดพลาดของการกลายพันธุ์ของตารางในทริกเกอร์


11

เป็นที่ทราบกันดีว่าคุณไม่สามารถใช้คำสั่ง DML ในตารางการกลายพันธุ์ภายในทริกเกอร์ ข้อความที่ตัดตอนมาจากเอกสารของ Oracle :

ตารางกลายพันธุ์เป็นตารางที่ถูกแก้ไขโดยคำสั่ง UPDATE, DELETE หรือ INSERT หรือตารางที่อาจได้รับการปรับปรุงโดยผลกระทบของข้อ จำกัด DELETE CASCADE

เซสชั่นที่ออกคำสั่งเรียกไม่สามารถสอบถามหรือแก้ไขตารางการกลายพันธุ์ ข้อ จำกัด นี้ป้องกันไม่ให้ทริกเกอร์เห็นชุดข้อมูลที่ไม่สอดคล้องกัน

อย่างไรก็ตามฉันไม่เข้าใจว่าทำไมทริกเกอร์การสาธิตนี้ไม่ได้ล้มเหลวด้วยข้อผิดพลาด "การกลายพันธุ์ตาราง" เมื่อฉันทำการinsert into empใช้ SQL Developer หรือ 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;

การแทรกเสร็จสมบูรณ์ด้วยidค่าถัดไปและอัพเดตempระเบียนทั้งหมด ฉันใช้ Oracle Database 11g Enterprise Edition รีลีส 11.2.0.1.0 ฉันได้อ่านทริกเกอร์ผสมแล้ว แต่ตัวอย่างไม่ได้ใช้


1
ที่ไม่เกี่ยวข้องกับคำถามของคุณ แต่: ไม่ไม่ใช้select max(id)การกำหนดหมายเลขที่ไม่ซ้ำกัน ทำไม่ได้ มันไม่ถูกต้องและจะไม่ขยายเช่นกัน
a_horse_with_no_name

ใช่ฉันรู้ว่า :) ตัวอย่างอาจไม่ดีในกรณีนี้ ... ค่าการสร้างอัตโนมัติควรนำมาใช้อย่างแน่นอนโดยใช้ลำดับและทริกเกอร์
Centurion

แน่นอนว่ามันแปลก Btw: นี่คือตัวอย่างSQLFiddle sqlfiddle.com/#!4/9e59f/2
a_horse_with_no_name

ขอบคุณสำหรับการแบ่งปันข้อมูลลิงค์เด็ด ๆ ไม่ทราบว่ามีเว็บไซต์ทดสอบ Oracle SQL ดังกล่าว :)
Centurion

คำตอบ:


12

มีข้อยกเว้น เมื่อคุณกำหนด a before insertทริกเกอร์ระดับแถวบนตารางและออกINSERTคำสั่งแถวเดียวtable is mutatingข้อผิดพลาดจะไม่ถูกยกขึ้น แต่ถ้าคุณกำหนดทริกเกอร์ชนิดเดียวกันและออกINSERTคำสั่งแบบหลายแถวข้อผิดพลาดจะถูกยกขึ้น นี่คือตัวอย่าง:

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

นี่คือinsertคำสั่งแถวเดี่ยวซึ่งจะไม่ทำให้เกิดข้อผิดพลาดในการกลายพันธุ์ของตาราง:

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

นี่คือคำสั่งแทรกหลายแถวซึ่งจะเพิ่มข้อผิดพลาดของการกลายพันธุ์ของตาราง:

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'

ดูเหมือนว่าจะเป็นผู้ร้าย คุณมีการอ้างอิงในคู่มือสำหรับพฤติกรรมนี้หรือไม่?
a_horse_with_no_name

@a_horse_with_no_name หากคุณเข้าถึง support.oracle.com ให้ค้นหาID 132569.1( ORA-4091 on BEFORE ROW TRIGGER with INSERT .. into SELECT statement)
นิโคลัส Krasnov

2
ขอบคุณ น่าสนใจพอข้อยกเว้นนี้ดูเหมือนว่าจะมีการบันทึกไว้ในคู่มือ 8i (!) เท่านั้น: docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/… (ส่วน " " การกลายพันธุ์และตารางการ จำกัด ") ฉันสามารถ ' หาคำแถลงนั้นในคู่มือปัจจุบัน
a_horse_with_no_name
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.