Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

làm thế nào để tạo một trình kích hoạt như ràng buộc khóa chính?

Chỉ vì bạn có vẻ có ý định nhìn thấy điều này không thành công và không lấy đi bất cứ điều gì từ các điểm của APC, điều này thoạt nhìn có vẻ hoạt động miễn là nó là một before kích hoạt:

create table t42 (id number);

create trigger trig42
before insert or update on t42
for each row
declare
  c number;
begin
  if :new.id is null then
    raise_application_error(-20001, 'ID is null');    
  end if;
  select count(*) into c from t42 where id = :new.id;
  if c > 0 then
    raise_application_error(-20002, 'ID is not unique');
  end if;
end;
/

Nó biên dịch và nếu bạn chèn dữ liệu, bạn sẽ có được hành vi như mong muốn:

insert into t42 values (1);

1 rows inserted.

insert into t42 values (1);

Error starting at line 20 in command:
insert into t42 values (1)
Error report:
SQL Error: ORA-20002: ID is not unique
ORA-06512: at "STACKOVERFLOW.TRIG42", line 9
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'

insert into t42 values (null);

Error starting at line 22 in command:
insert into t42 values (null)
Error report:
SQL Error: ORA-20001: ID is null
ORA-06512: at "STACKOVERFLOW.TRIG42", line 5
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'

select * from t42;

        ID
----------
         1 

Điều đó dường như làm những gì bạn muốn. Nhưng không phải nếu bạn có nhiều hơn một phiên. Tôi đã không cam kết trong phiên này; trong một phiên khác tôi có thể làm:

insert into t42 values (1);

1 row created.

select * from t42;

        ID
----------
         1

1 row selected.

Hmm, lạ thật. Chà, có thể nó bị hoãn lại ... hãy cam kết cả hai:

commit;

select * from t42;
        ID
----------
         1
         1

2 rows selected.

Ối. Một khi phiên không thể nhìn thấy dữ liệu chưa được cam kết của phiên khác, vì vậy điều này sẽ không bao giờ hoạt động.

Ngoài ra, vấn đề bảng biến đổi tự thể hiện khi chúng ta chèn nhiều hàng trong một câu lệnh:

SQL> insert into t42 select level+1 from dual connect by level <= 5; 
insert into t42 select level+1 from dual connect by level <= 5
            *
ERROR at line 1:
ORA-04091: table STACKOVERFLOW.T42 is mutating, trigger/function may not see it
ORA-06512: at "STACKOVERFLOW.TRIG42", line 7
ORA-04088: error during execution of trigger 'STACKOVERFLOW.TRIG42'


SQL> 

Rất tiếc.

Ngay cả với after kích hoạt và một gói để giải quyết vấn đề bảng thay đổi, bạn vẫn gặp sự cố này (tôi nghĩ vậy), trừ khi bạn khóa toàn bộ bảng cho mỗi lần chèn hoặc cập nhật. Như APC đã nói, ràng buộc được thực hiện sâu trong ruột của cơ sở dữ liệu, không phải ở cấp độ này.

Không phải khi bạn có nhiều hơn một phiên, không. Và ngay cả trong một phiên, trừ khi bạn có chỉ mục trên cột, hiệu suất sẽ không chia tỷ lệ như count(*) sẽ dần dần chậm hơn. Và nếu bạn có một chỉ mục, tốt, tại sao không đặt nó trở thành một chỉ mục duy nhất ngay từ đầu?

Cuối cùng, từ nguyên tắc thiết kế trình kích hoạt :



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Nhiều giá trị tối đa trong một truy vấn

  2. Oracle PL / SQL:Cách in một loại bảng

  3. mẫu tên không hợp lệ khi cố gắng chuyển ánh xạ đối tượng loại oracle tùy chỉnh

  4. Thông báo thay đổi Cơ sở dữ liệu Oracle

  5. Lỗi PLS-00539 và PLS-00538 khi tạo các hàm UDT