Trigger

Trigger

I Khái quát về trigger

I.1 Trigger là gì?

Trigger có thể được xem là một dạng đặc biệt của thủ tục nội tại, bởi vì bên trong nội dung của trigger lưu trữ các câu lệnh dùng để thực hiện một số hành động nào đó mà người lập trình sẽ chỉ ra. Tuy nhiên khác với thủ tục nội tại, trigger hoàn toàn không có tham số. Ngoài ra chúng ta không thể gọi thực hiện trực tiếp trigger bằng lệnh EXECUTE như thủ tục nội tại hoặc bằng bất kỳ một lệnh nào khác, thay vào đó trigger sẽ được thực hiện một cách tự động khi dữ liệu của bảng có liên quan đến trigger bị cập nhật.

Chính nhờ vào tính năng đặc biệt là tự động thực hiện mà nội dung các lệnh bên trong trigger được dùng cho các công việc sau :

§ Kiểm tra các ràng buộc toàn vẹn dữ liệu phức tạp.

§ Thực hiện các xử lý được thiết kế thi hành tại server (trong mô hình client/server). Các xử lý mà ta muốn chúng sẽ được tự động thực hiện khi có thao tác INSERT, UPDATE, hoặc DELETE xảy ra.

§ Trigger cũng được dùng để thay thế các constraint trong trường hợp ta muốn việc kiểm tra ràng buộc dữ liệu kèm theo các câu thông báo thích hợp theo ý muốn người dùng.

I.2 Mở rộng ràng buộc toàn vẹn dữ liệu với các trigger

Có 3 thao tác cơ bản làm thay đổi dữ liệu trên các bảng của cơ sở dữ liệu đó là thao tác thêm (insert), thao tác sửa (update) và thao tác xoá (delete). Như vậy, để bảo đảm dữ liệu nhất quán và đúng đắn, ta cần kiểm tra việc thực hiện của 3 thao tác này.

Có 2 cách để kiểm tra : kiểm tra mức giao diện và kiểm tra mức cơ sở dữ liệu.

– Kiểm tra mức giao diện : công việc này chính là công việc lập trình trên các màn hình giao diện.

– Kiểm tra mức cơ sở dữ liệu : công việc này được thực hiện bởi các đối tượng constraint hoặc trigger.

Đối với các ràng buộc toàn vẹn dữ liệu đơn giản như kiểm tra các ràng buộc miền giá trị, kiểm tra các ràng buộc giữa các thuộc tính trên cùng một bảng dữ liệu,… ta nên sử dụng đối tượng constraint.

Đối với các ràng buộc toàn vẹn dữ liệu phức tạp khác – là những qui tắc được định nghĩa dùng để kiểm tra tính toàn vẹn của dữ liệu trên nhiều cột hoặc nhiều dòng của các bảng khác nhau. Khi đó bắt buộc chúng ta phải sử dụng đối tượng trigger, đối tượng này cho phép chúng ta xây dựng các câu lệnh bên trong nó với mục tiêu là các câu lệnh này sẽ được thực hiện khi các thao tác làm thay đổi dữ liệu xảy ra trên bảng dữ liệu màn nó gắn.

Một trigger gắn với duy nhất một đối tượng table hoặc một đối tượng view.

I.3 Các dạng ràng buộc toàn vẹn dữ liệu nên dùng trigger

Vấn đề mà chúng tôi muốn đề cập ở đây là trong những trường hợp nào chúng ta sẽ nên sử dụng trigger để xây dựng các kiểm tra ràng buộc toàn vẹn dữ liệu.

Trên MS SQL server, có 2 cách thực hiện ràng buộc toàn vẹn dữ liệu:

  • Ràng buộc toàn vẹn dữ liệu bằng phương pháp mô tả (declarative data integrity ):

Thực hiện ràng buộc dữ liệu theo phương pháp này chính là các công việc xác định ràng buộc khoá chính, khoá ngoại, kiểm tra miền giá trị,… và mô tả chúng tại thời điểm tạo table.

Đặc điểm cần biết của phương pháp này là việc kiểm tra sẽ được thực hiện trước khi cho phép ghi vào table.

  • Ràng buộc toàn vẹn dữ liệu bằng phương pháp theo thủ tục (procedural data integrity ):

Trong phương pháp này, việc ràng buộc toàn vẹn dữ liệu được xác định bởi tập hợp các câu lệnh T-SQL. Các câu lệnh chứa bên trong đối tượng Trigger, chúng sẽ được gọi thi hành khi có thao tác thêm, xoá, hoặc sửa dữ liệu xảy ra trên table tương ứng.

Đặc điểm cần biết của phương pháp này là việc kiểm tra sẽ được thực hiện sau khi dữ liệu được ghi vào table.

I.4 Khi nào thì sử dụng Trigger ?

Để giải đáp thoả đáng vấn đề này, chúng ta cùng nhau xem xét ví dụ sau :

Cho một cơ sở dữ liệu có cấu trúc sau :

KHACH_HANG(ID_KHG, Ten_NCC)

PHIEU_XUAT(ID_PX, So_PX, Ngay_PN,#ID_KHG)

CT_PHIEU_XUAT(#ID_PX, #ID_HH, SoLuong, DonGia,ThanhTien)

DM_HANG_HOA(ID_HH, Ten_HH, DonGiaHienHanh)

Để bảo đảm tính nhất quán và chính xác của dữ liệu, cần thực hiện các yêu cầu ràng buộc toàn vẹn dữ liệu :

1. KHACH_HANG : Một khách hàng có 1 mã duy nhất dùng để phân biệt khách hàng này với khách hàng khác, có 1 tên khách hàng duy nhất.

2. DM_HANG_HOA : Một hàng hoá có 1 mã hàng hoá duy nhất dùng để phân biệt với hàng hoá khác, có 1 tên hàng hoá và 1 đơn giá bán hiện tại duy nhất.

3. PHIEU_XUAT : Một phiếu xuất có 1 mã duy nhất dùng để phân biệt với phiếu xuất khác, có 1 số phiếu xuất , 1 ngày xuất xác định.

Một phiếu xuất liên quan đến duy nhất 1 khách hàng.

Một phiếu xuất có ít nhất 1 chi tiết xuất.

4. CT_PHIEU_XUAT : Một chi tiết xuất có mã phiếu xuất và mã hàng hoá dùng để xác định khoá của quan hệ. Khoá này dùng để phân biệt với chi tiết xuất khác, có 1 giá trị số lượng xác định, 1 đơn giá tương ứng với đơn giá hiện hành của hàng hoá lấy từ thuộc tính DonGiaHienHanh của table DM_HANG_HOA. Giá trị của ThanhTien được tính toán dựa trên công thức ThanhTien=SoLuong* DonGia

Câu hỏi đặt ra : với các yêu cầu ràng buộc toàn vẹn dữ liệu ở trên, yêu cầu nào cần phải sử dụng trigger để cài đặt?

Câu trả lời : chỉ có ràng buộc 1 đơn giá tương ứng với đơn giá hiện hành của hàng hoá lấy từ thuộc tính DonGiaHienHanh của table DM_HANG_HOA là thật sự cần phải sử dụng trigger để giải quyết vấn đề. Các ràng buộc còn lại ta có thể sử dụng theo phương pháp mô tả.

Các trường hợp sử dụng trigger :

§ Quan điểm cơ bản cần nghĩ đến trước tiên là chỉ những ràng buộc dữ liệu nào không thể dùng phương pháp mô tả (declarative data integrity) thì mới dùng trigger để giải quyết. Tuy nhiên, bạn không nhất thiết phải tuân thủ theo quan điểm này, trên thực tế bạn hoàn toàn có thể dùng trigger để thay thế cho constraint trong trường hợp bạn muốn tự mình kiểm soát và cho ra các câu thông báo thích hợp người dùng.

§ Khi có sự thay đổi dữ liệu trên 1 table và chúng ta muốn dữ liệu trên 1 hay nhiều table khác cũng tự động thay đổi theo cho phù hợp.

Ví dụ : chúng ta có các table có cấu trúc sau

Create table DON_GIA_HANG_HOA

(

ID_DGHH numeric identity(1,1) primary key,

ID_HH varchar(50)not null,

Ngay_DGHH datetime,

Gia_DGHH numeric,

HienHanh tinyint default 1

foreign key(ID_HH) references DM_HANG_HOA(ID_HH),

check(Gia_DGHH>0)

)

Create Table DM_HANG_HOA

(

ID_HH varchar(50) primary key,

Ten_HH varchar(50),

DonGiaHienHanh numeric not null

check(DonGiaHienHanh>0)

)

Yêu cầu : Khi thêm mới mẫu tin trên table DON_GIA_HANG_HOA cần update lại mục DonGiaHienHanh trên table DM_HANG_HOA sao cho DM_HANG_HOA.DonGiaHienHanh = DON_GIA_HANG_HOA.Gia_DGHH

Giải quyết vấn đề : Với các yêu cầu ràng buộc dữ liệu này, ta cần phải dùng trigger để thực hiện. Cụ thể phải thực hiện như thế nào chúng tôi sẽ đề cập ở phần sau của chương này (tại mục ?).

§ Trên thực tế đôi khi người lập trình muốn thay đổi cấu trúc lưu trữ của dữ liệu với mục tiêu tăng tốc độ xử lý hoặc việc xử lý tính toán dễ dàng hơn, điều này thường dẫn đến việc phá vỡ tính chuẩn của cơ sở dữ liệu và làm tăng thêm ràng buộc toàn vẹn dữ liệu. Ví dụ, ta có trường hợp sau :

Create Table PHIEU_XUAT

(

ID_PX numeric identity(1,1) primary key,

So_PX varchar(50) unique,

Ngay_PX datetime,

ID_KHG varchar(50),

TongSoTien numeric,

Foreign key(ID_KHG) References KHACH_HANG(ID_KHG)

)

Cột TongSoTien được bổ sung vào table PHIEU_XUAT với ý nghĩa dùng để chứa giá trị tổng số tiền của phiếu xuất. Giá trị này bằng tổng các giá trị chứa trên cột ThanhTien của cùng phiếu xuất trên table CT_PHIEU_XUAT. Vấn đề khó khăn ở đây là khi thêm, xoá mẫu tin, hoặc sửa đổi giá trị của cột ThanhTien trên CT_PHIEU_XUAT, tính đúng đắn của cột TongSoTien trên PHIEU_XUAT phải luôn được bảo đảm.

Gặp các tình huống như thế này, bạn không cần phải đắn đo khi quyết định sử dụng trigger.

§ Nếu bạn muốn cơ sở dữ liệu có những thông báo lỗi thích hợp theo ý muốn khi thao tác thay đổi dữ liệu vi phạm ràng buộc toàn vẹn, bạn nên dùng trigger.

§ Tất cả các xử lý mà bạn muốn chúng tự động thực hiện tại phía server khi có thao tác dữ liệu INSERT, UPDATE, hoặc DELETE xảy ra.

I.5 Các đặc trưng và hạn chế

§ Từ 1 trigger có thể xây dựng bên trong nó các câu lệnh tác động lên cột của table bất kỳ trong cơ sở dữ liệu hoặc tới các đối tượng bên ngoài cơ sở dữ liệu hiện hành.

§ Có thể áp dụng trigger cho đối tượng View.

§ Một trigger có thể thực hiện nhiều hành động (multiple actions), và nó có thể được kíck hoạt bởi nhiều hơn 1 biến cố (các biến cố gồm : insert, delete, update).

§ Trigger không thể được tạo trên một table tạm(temporary table, là table được tạo với tên table có ký tự # hoặc ## phía trước) hoặc table hệ thống (system table). Tuy nhiên, cần chú ý rằng, các câu lệnh bên trong trigger hoàn toàn có thể tham chiếu đến nội dung bên trong các table tạm và table hệ thống.

§ Một hạn chế quan trọng mà bạn cần quan tâm là các trigger loại INSTEAD OF DELETE và INSTEAD OF UPDATE không thể được định nghĩa trên các table có chứa khoá ngoại và trên dây quan hệ nối từ table chứa nó thông qua khoá ngoại đến table khác đã có thiết đặt tương ứng trên các dây quan hệ tính chất Cascade Delete Related Records và Cascade update Related Fieds.

referrelative=”t” o:spt=”75″ coordsize=”21600,21600″>ath o:connecttype=”rect” gradientshapeok=”t” o:extrusionok=”f”>ath>

Ví dụ :

Trong mối quan hệ ở hình trên, nếu ta thiết đặt tính Cascade Delete Related Records của dây quan hệ thì việc tạo trigger loại Instead Of Delete sẽ không thể thực hiện thành công.

I.6 Các biến cố trigger

Có 3 biến cố tự kích hoạt 1 trigger : INSERT, UPDATE, và DELETE. Các biến cố xảy ra trên đối tượng table hoặc view tại thời điểm các thao tác dữ liêu tương ứng tác động lên các đối tượng này. Ta không thể gọi thi hành trực tiếp 1 trigger.

Tồn tại các trường hợp chắc chắn là khi một sự kiện sửa hoặc xoá dữ liệu xảy ra nhưng không kích hoạt trigger, đó là các trường hợp sau:

– Khi sử dụng câu lệnh TRUNCATE TABLE sẽ không làm kích hoạt trigger được định nghĩa cho biến cố DELETE. Một điều quan trọng cần quan tâm đối với các trigger là nếu giao tác (transaction) không thành công sẽ tự động quay lui (rolled back). Bởi vì, câu lệnh TRUNCATE TABLE không là một biến cố được ghi nhận vào sổ ghi nhận biến cố, nó không thể được quay lui vì vậy nó không kích hoạt trigger DELETE.

– Câu lệnh WRITETEXT cũng không là nguyên nhân gây kích hoạt trigger INSERT hoặc UPDATE.

I.7 Cơ chế hoạt động của trigger

Khi thực hiện việc thêm mới mẫu tin vào một table, thao tác này sẽ kích hoạt một trigger, trigger lưu trữ dữ liệu của mẫu tin vừa thêm mới vào một table có tên là Inserted. Tương tự, khi thực hiện việc xoá mẫu tin của một table, thao tác này sẽ kích hoạt một trigger, trigger lưu trữ dữ liệu của mẫu tin vừa xoá vào một table có tên là Deleted.

Cấu trúc của hai bảng này hoàn toàn giống với cấu trúc của bảng dữ liệu liên quan đến trigger khi tạo ra. Thật ra hai bảng này chỉ tồn tại trong bộ nhớ của máy tính (RAM) được xem như là hai bảng luận lý mà chúng ta có thể sử dụng trong các xử lý của trigger. Chúng ta không thể tham chiếu trực tiếp trong tiện ích SQL Query Analyzer hoặc bên trong các thủ tục nội tại.

Chúng ta đã đề cập đến đến cơ chế hoạt động của trigger liên quan đến 2 thao tác thêm và xoá dữ liệu. Thế còn đối với thao tác sửa đổi dữ liệu (update) thì sao ?

Lệnh UPDATE trong Microsoft SQL Server được xem như là sự phối hợp của hai lệnh DELETE và INSERT (xóa bỏ dữ liệu cũ và thêm vào dữ liệu mới sau khi sửa đổi) do thế mà đối với các trigger liên quan đến việc sửa đổi dữ liệu thì chúng ta có thể tham chiếu đến cả hai bảng trung gian Inserted và Deleted.

Trong đó bảng Deleted sẽ chứa đựng thông tin của các dòng dữ liệu đã bị hủy bỏ – các dòng dữ liệu cũ trước khi sửa đổi, bảng Inserted sẽ chứa đựng thông tin của các dòng dữ liệu mới vừa thêm vào – các dòng dữ liệu sau khi sửa đổi.

Một khái niệm quan trọng liên quan đến cơ chế hoạt động của trigger mà chúng tôi muốn đề cập ở phần này, đây là khái niệm liên quan đến phần bổ sung mới của phiên bản SQL Server 2000, khái niệm INSTEAD OF và AFTER.

§ Trigger loại INSTEAD OF sẽ bỏ qua hành động kích hoạt trigger (Các thao tác insert, delete, update), thay vào đó nó sẽ thực hiện các câu lệnh bên trong trigger. Cần lưu ý là nó sẽ bỏ qua hành động tác động đến cơ sở dữ liệu nhưng việc lưu trữ dữ liệu vào các bảng inserted (đối với thao các insert), deleted (đối với thao tác delete) vẫn được thực hiện. Ví dụ : một câu lệnh update tác động tới một table chứa trigger loại INSTEAD OF, các câu lệnh T-SQL bên trong trigger sẽ được thi hành, nó đóng vai trò thay thế câu lệnh update. Đặc tính này cho phép bạn chỉ định các câu lệnh xử lý phức tạp trong trigger nhằm làm tăng thêm lệnh thay đổi dữ liệu trên table.

Trigger loại INSTEAD OF có thể định nghĩa trên đối tượng table hoặc view

§ Trigger loại AFTER là loại mặc định (cũng chính là loại có từ khoá khai báo FOR), nó có vai trò như là phần bổ sung của hành động kích hoạt trigger. Các câu lệnh bên trong trigger loại này chỉ được thi hành sau khi hành động kích hoạt đã được thực hiện rồi. Cần chú ý : là các ràng buộc toàn vẹn loại mô tả sẽ được thực hiện trước, kế đó các câu lệnh bên trong trigger sẽ được thực hiện sau. Trigger loại AFTER chỉ được phép định nghĩa trên duy nhất đối tượng table (không thể định nghĩa trên view).

Trên một table, nếu muốn, bạn có thể định nghĩa cả 2 loại trigger. Nếu bạn định nghĩa cả 2 loại trigger và các constraint cho một table, thứ tự thi hành sẽ là trigger INSTEAD OF, các constraint được xử lý và sau cùng là trigger AFTER. Nếu các constraint bị vi phạm (có nghĩa là việc kiểm tra ràng buộc toàn vẹn của các constraint phát hiện có vi phạm tính toàn vẹn dữ liệu), các hành động của trigger INSTEAD OF sẽ được quay lui, trigger AFTER không thi hành nếu các constraint bị vi phạm hoặc nếu có một số biến cố khác làm cho việc sửa đổi dữ liệu trên table bị lỗi.

Giống như các thủ tục nội tại, trigger có thể được lồng đến 32 cấp và có thể được kich hoạt đệ qui.

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: