Tại sao tôi KHÔNG nhận được một lỗi bảng đột biến trong kích hoạt?


11

Điều này (hoặc ít nhất là) được biết rằng bạn không thể sử dụng các câu lệnh DML trên bảng đột biến bên trong trình kích hoạt. Một đoạn trích từ tài liệu của Oracle :

Bảng đột biến là một bảng đang được sửa đổi bởi một câu lệnh CẬP NHẬT, XÓA hoặc INSERT hoặc một bảng có thể được cập nhật bởi các tác động của ràng buộc XÓA CASCADE.

Phiên phát hành câu lệnh kích hoạt không thể truy vấn hoặc sửa đổi bảng đột biến. Hạn chế này ngăn không cho trình kích hoạt nhìn thấy một tập hợp dữ liệu không nhất quán.

Tuy nhiên, tôi không thể hiểu tại sao trình kích hoạt demo này không bị lỗi với "bảng đột biến" khi tôi thực hiện insert into empsử dụng SQL Developer hoặc 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;

Việc chèn hoàn thành thành công với idgiá trị tiếp theo và cập nhật tất cả các empbản ghi. Tôi đang sử dụng Cơ sở dữ liệu Oracle 11g Phiên bản doanh nghiệp Phiên bản 11.2.0.1.0. Tôi đã đọc về các kích hoạt hợp chất nhưng mẫu không sử dụng chúng.


1
Không liên quan đến câu hỏi của bạn, nhưng: KHÔNG sử dụng select max(id)để gán các số duy nhất. Chỉ không. Nó đơn giản là không chính xác và nó sẽ không mở rộng quy mô.
a_horse_with_no_name

Vâng, tôi biết điều đó :) Ví dụ có lẽ không tốt lắm trong trường hợp này ... Các giá trị tự động nên được thực hiện chắc chắn bằng cách sử dụng trình tự và trình kích hoạt.
Centurion

Điều này chắc chắn là lạ. Btw: đây là một ví dụ SQLFiddle sqlfiddle.com/#!4/9e59f/2
a_horse_with_no_name

Cảm ơn đã chia sẻ thông tin, liên kết mát mẻ. Không biết có trang web thử nghiệm Oracle SQL như vậy :)
Centurion

a_horse_with_no_name: Một ví dụ khác: Fiddle-test-2 (SET lương = lương + 10)
ypercubeᵀᴹ

Câu trả lời:


12

Có một ngoại lệ. Khi bạn xác định before inserttrình kích hoạt cấp hàng trên bảng và đưa ra INSERTcâu lệnh hàng đơn , table is mutatinglỗi sẽ không được nêu ra. Nhưng nếu bạn xác định cùng loại trình kích hoạt và đưa ra INSERTcâu lệnh nhiều hàng , lỗi sẽ được đưa ra. Đây là một ví dụ:

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

Đây là một insertcâu lệnh một hàng , sẽ không làm tăng lỗi bảng đột biến:

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

Dưới đây là một câu lệnh chèn nhiều hàng, sẽ làm tăng lỗi bảng đột biến:

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'

Đó dường như là thủ phạm. Bạn có một tài liệu tham khảo trong hướng dẫn cho hành vi này?
a_horse_with_no_name

@a_horse_with_no_name nếu bạn có quyền truy cập vào support.oracle.com, hãy tìm kiếm ID 132569.1( ORA-4091 on BEFORE ROW TRIGGER with INSERT .. into SELECT statement).
Nicholas Krasnov

2
Cảm ơn. Thú vị đủ ngoại lệ này dường như được chỉ được ghi lại trong 8I hướng dẫn sử dụng (!): Docs.oracle.com/cd/F49540_01/DOC/server.815/a68003/... (phần " 'biến đổi và kìm hãm Bàn ') Tôi có thể' t tìm thấy tuyên bố đó trong hướng dẫn sử dụng hiện tại.
a_horse_with_no_name
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.