Hãy thử một trình kích hoạt phức hợp:
CREATE OR REPLACE TRIGGER compound_trigger_name
FOR INSERT OR UPDATE OF salary ON treballa
COMPOUND TRIGGER
TYPE Departments_t IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
Departments Departments_t;
BEFORE EACH ROW IS
BEGIN
-- collect updated or inserted departments
Departments( :new.department ) := :new.department;
END BEFORE EACH ROW;
AFTER STATEMENT IS
sum_sal NUMBER;
BEGIN
-- for each updated department check the restriction
FOR dept IN Departments.FIRST .. Departments.LAST
LOOP
SELECT sum(salary) INTO sum_sal FROM treballa WHERE department = dept;
IF sum_sal > 1000 THEN
raise_application_error(-20123, 'The total salary for department '||dept||' cannot exceed 1000');
END IF;
END LOOP;
END AFTER STATEMENT;
END compound_trigger_name;
/
========CHỈNH SỬA - một vài câu hỏi và câu trả lời ===========
H:Tại sao xảy ra lỗi bảng đột biến?
Đ:Điều này được mô tả trong tài liệu:
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#g1699708
Hỏi:làm cách nào để tránh lỗi bảng thay đổi?
Đ:Tài liệu khuyến nghị sử dụng trình kích hoạt coumpound, hãy xem phần sau: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CHDFEBFJ
H:Trình kích hoạt phức hợp là gì và nó hoạt động như thế nào?
A:Đây là một chủ đề rất lớn, vui lòng tham khảo tài liệu tại đây: http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHEFGFD
Nói một cách ngắn gọn
:đây là một loại trình kích hoạt đặc biệt giúp bạn có thể kết hợp bốn loại trình kích hoạt riêng biệt:BEFORE statement
, BEFORE-for each row
, AFTER for each row
và AFTER statament
vào một khai báo. Nó giúp dễ dàng triển khai một số tình huống trong đó cần phải chuyển một số dữ liệu từ trình kích hoạt này sang trình kích hoạt khác. Vui lòng nghiên cứu liên kết trên để biết thêm chi tiết.
Hỏi:Nhưng điều gì thực sự làm "Departments( :new.department ) := :new.department;
?
A:Khai báo này lưu trữ một số phòng ban vào một mảng kết hợp.
Mảng này được khai báo trong một phần khai báo của trình kích hoạt phức hợp:
TYPE Departments_t IS TABLE OF treballa.department%TYPE INDEX BY varchar2(100);
Departments Departments_t;
Tài liệu liên quan đến trình kích hoạt kết hợp cho biết: http ://docs.oracle.com/cd/B28359_01/appdev.111/b28370/triggers.htm#CIHJBEFE
Ở trên có nghĩa là Departments
biến chỉ được khởi tạo một lần khi bắt đầu toàn bộ quá trình, ngay sau khi trình kích hoạt kích hoạt. "Thời lượng câu lệnh kích hoạt" có nghĩa là biến này bị hủy sau khi trình kích hoạt kết thúc.
Câu lệnh này:Departments( :new.department ) := :new.department;
lưu trữ một số phòng ban trong mảng kết hợp. Nó nằm trong BEFORE EACH ROW
, sau đó nó được thực thi cho mỗi hàng được cập nhật (hoặc chèn) bằng câu lệnh update / insert.
:new
và :old
là các từ giả, bạn có thể tìm thấy thêm thông tin về chúng tại đây: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/triggers.htm#LNPLS99955
Tóm lại::new.department
truy xuất giá trị mới của department
cột- cho hàng hiện được cập nhật (giá trị được cập nhật - SAU khi cập nhật), trong khi :old.department
cung cấp giá trị cũ của cột này (TRƯỚC khi cập nhật).
Bộ sưu tập này sau đó được sử dụng trong AFTER STATEMENT
, khi bộ ba chọn tất cả các phòng ban được cập nhật (trong FOR-LOOP), đối với mỗi lần khởi hành sẽ kích hoạt SELECT SUM(salary) ...
và sau đó kiểm tra xem số tiền này có nhỏ hơn 1000 không
Hãy xem xét một bản cập nhật đơn giản:UPDATE treballa SET salary = salary + 10
. Đây là một câu lệnh cập nhật duy nhất, nhưng thay đổi nhiều hàng cùng một lúc. Thứ tự thực hiện trình kích hoạt của chúng tôi như sau:
- Dữ liệu cập nhật được kích hoạt:
UPDATE treballa SET salary = salary + 10
- Phần khai báo của trình kích hoạt được thực thi, đó là:
Departments
biến được khởi tạo -
BEFORE EACH ROW
được thực thi, riêng biệt cho từng hàng được cập nhật - số lần có hàng được cập nhật. Tại nơi này, chúng tôi thu thập tất cả các phòng ban từ các hàng đã thay đổi. -
AFTER STATEMENT
phần được thực thi. Tại thời điểm này, bảng đã được cập nhật - tất cả các hàng đã có lương mới, cập nhật. Chúng tôi lặp lại các phòng ban được lưu trongDepartments
và đối với mỗi bộ phận, chúng tôi kiểm tra xem tổng tiền lương có nhỏ hơn hoặc bằng 1000 hay không. Nếu tổng số tiền này> 1000 cho bất kỳ bộ phận nào trong số các bộ phận này, thì một lỗi sẽ xảy ra và toàn bộ bản cập nhật sẽ bị hủy bỏ và quay trở lại. Nếu không, trình kích hoạt kết thúc và quá trình cập nhật được thực hiện (nhưng dù sao bạn cũng cần phải thực hiện những thay đổi này).
H:Mảng kết hợp là gì và tại sao chỉ sử dụng loại tập hợp này chứ không phải các tập hợp khác (varray hoặc bảng lồng nhau)?
A:Bộ sưu tập PL / SQL là một chủ đề rất lớn. Theo liên kết này để tìm hiểu chúng: http:// docs.oracle.com/cd/E11882_01/appdev.112/e25519/composites.htm#LNPLS005
Nói ngắn gọn
- Mảng kết hợp (hoặc chỉ mục theo bảng) giống như một bản đồ trong java (hashmap, treemap, v.v.) - nó là một tập hợp các cặp khóa-giá trị và mỗi khóa là duy nhất . Bạn có thể đặt cùng một khóa nhiều lần vào mảng này (với các giá trị khác nhau), nhưng khóa này sẽ chỉ được lưu trữ một lần - nó là duy nhất.
Tôi đã sử dụng nó để có được tập hợp các phòng ban duy nhất.
Hãy xem xét lại ví dụ cập nhật của chúng tôi:UPDATE treballa SET salary = salary + 10
- lệnh này chạm vào hàng trăm hàng có cùng một bộ phận. Tôi không muốn một bộ sưu tập có cùng một bộ phận được sao chép 100 lần, tôi cần một bộ bộ phận duy nhất và tôi muốn thực hiện truy vấn của chúng tôi SELECT sum()...
chỉ một lần cho mỗi bộ phận, không phải 100 lần. Với sự trợ giúp của mảng sssociative, nó được thực hiện tự động - tôi nhận được bộ mô tả duy nhất.