Cú pháp CREATE TRIGGER trigger_name ON { table | view } FOR INSERT AS sql_statement Ví dụ Với CSDL đã tạo ban đầu, viết một trigger INSERT trên bảng ORDERS sao cho khi thêm một dòng
Trang 11 Table
Sử dụng cú pháp CREATE TABLE để xây dựng 5 bảng theo đúng các yêu cầu sau:
- Bảng khách hàng (Customers) gồm các cột: CustomerID, CompanyName, Phone, Fax, Address, ContactName Trong đó quy định CustomerID là khóa chính
CustomerID Nchar(5) NOT NULL CompanyName Nvarchar(40) NOT NULL Phone Nvarchar(24) NULL Fax Nvarchar(24) NULL Address Nvarchar(60) NULL ContactName Nvarchar(30) NULL
- Bảng nhân viên (Employees) gồm các cột: EmployeeID, LastName, FirstName, BirthDate, Photo, IDNo, Notes, HireDate Trong đó quy định EmployeeID là khóa chính và tăng tự
động bắt đầu từ 1, IDNo là duy nhất (Unique)
NOT NULL
EmployeeID Int IDENTITY (1,1) NOT NULL LastName Nvarchar(20) NOT NULL FirstName Nvarchar(14) NOT NULL
- Bảng hàng hóa (Products) gồm các cột: ProductID, ProductName, UnitPrice Trong đó
quy định ProductID là khóa chính, kiểm tra giá trị cột UnitPrice > 0
NOT NULL
ProductID Int IDENTITY (1,1) NOT NULL ProductName Nvarchar(40) NOT NULL
Trang 2UnitPrice Money NULL
- Bảng đơn đặt hàng (Orders) gồm các cột: OrderID, OrderDate, TotalAmount, CustomerID, EmployeeID Trong đó quy định OrderID là khóa chính và tự động tăng bắt
đầu từ 10248, giá trị mặc định cho OrderDate là ngày hiện hành, giá trị mặc định cho cột TotalAmount là 0, CustomerID là khóa ngoại tham chiếu qua bảng Customers, EmployeeID là khóa ngoại tham chiếu qua bảng Employees
NOT NULL
OrderID Int IDENTITY (10248,1) NOT NULL
- Bảng chi tiết đặt hàng (OrderDetails) gồm các cột: OrderID, ProductID, UnitPrice, Quantity Trong đó quy định OrderID, ProductID là khóa chính, OrderID là khóa ngoại
tham chiếu qua bảng Orders, ProductID là khóa ngoại tham chiếu qua bảng Products, kiểm tra giá trị cột UnitPrice > 0 và giá trị cột Quantity > 0
Quantity Smallint NOT NULL
Lưu 5 câu lệnh CREATE TABLE vừa tạo vào một tập tin có phần mở rộng là *.sql để sau này có thể tạo nhanh lại các bảng
2 Triggers
2.1 Khái niệm
Trigger là một loại stored procedure được định nghĩa đặc biệt để thực thi một cách tự động khi có một câu lệnh UPDATE, INSERT hoặc DELETE tác động vào table Trigger là một công cụ mạnh, khi dữ liệu bị sửa đổi nó sẽ tự động thực hiện việc ép buộc các giao dịch
Trang 3sửa đổi này theo các qui tắc đã định (các ràng buộc dữ liệu) nhằm mục đích đảm bảo tính toàn vẹn dữ liệu
Các table có thể có nhiều trigger Câu lệnh CREATE TRIGGER có thể được định nghĩa với các mệnh đề FOR UPDATE, FOR INSERT, hoặc FOR DELETE
Các câu lệnh chứa bên trong các trigger không có gì khác với stored procedure
Các trigger thực thi sau khi các câu lệnh bên trong chúng hoàn thành Nếu tồn tại câu lệnh sai với một lỗi, ví dụ như là một lỗi vi phạm ràng buộc hoặc lỗi cú pháp, trigger sẽ không được thực thi
2.2 Tạo trigger
2.2.1 Tạo trigger bằng công cụ Enterprise Manager
1 Chọn server group Æ chọn server
2 Chọn Databases Æ chọn database chứa table muốn tạo trigger Æ click Tables
3 Trong khung trình bày các đối tượng table của database Æ click phải chuột tại tên table
muốn tạo trigger Æ chọn All Tasks Æ chọn Manage Triggers …
4 Tại mục Name, click <new>
Trang 45 Trong hộp thoại Text, gõ vào nội dung của trigger
6 Click Check Syntax để kiểm tra lỗi cú pháp
2.2.2 Tạo trigger sử dụng T-SQL
2.2.2.1 Tạo trigger loại INSERT TRIGGER
Khái niệm
Trigger loại insert sẽ tự động thi hành các câu lệnh bên trong nó khi có thao tác insert xảy ra trên table mà nó gắn INSERT TRIGGER được dùng trong các trường hợp sau:
Thông báo, khuyến cáo, nhắc nhở, phản hồi thông tin khi có thao tác thêm mới mẫu tin
Thực hiện các xử lý tính toán và cập nhật dữ liệu dựa trên các giá trị vừa thêm mới
Tự động kiểm tra các vi phạm ràng buộc khóa chính, khóa ngoại
Cú pháp
CREATE TRIGGER trigger_name ON { table | view }
FOR INSERT
AS
sql_statement
Ví dụ
Với CSDL đã tạo ban đầu, viết một trigger INSERT trên bảng ORDERS sao cho khi thêm một dòng dữ liệu vào bảng ORDERS phải kiểm tra các cột khóa ngoại: cột CustomerID trong
Trang 5bảng CUSTOMERS, cột EmployeeID trong bảng EMPLOYEES
CREATE TRIGGER [ORDERS_INSERT] ON [ORDERS]
FOR INSERT
AS
Kiem tra cot CustomerID trong table CUSTOMERS
DECLARE @Cust int, @Emp int, @Msg varchar (50)
SET @Cust=1
IF EXISTS (SELECT *
FROM INSERTED
WHERE CustomerID IN
(SELECT CustomerID FROM CUSTOMERS))
SET @Cust=0
Kiem tra cot EmployeeID trong table EMPLOYEES
SET @Emp=1
IF EXISTS (SELECT *
FROM EMPLOYEES n, INSERTED i
WHERE n.EmployeeID = i.EmployeeID)
SET @Emp=0
Xet gia tri cac bien @Cust, @Emp
Neu @Cust=0 va @Emp=0 thi luu mau tin moi them
Nguoc lai, thong bao loi vi pham rang buoc khoa ngoai
SET @Msg=
CASE
WHEN @Cust=0 AND @Emp=0 then 'TC'
WHEN @Cust=0 AND @Emp=1 then 'Khong ton tai EmployeeID trong table EMPLOYEES'
WHEN @Cust=1 AND @Emp=0 then 'Khong ton tai CustomerID trong table CUSTOMERS'
WHEN @Cust=1 AND @Emp=1 then 'Khong ton tai EmployeeID trong table EMPLOYEES, CustomerID trong table CUSTOMERS'
END
IF @Msg='TC'
PRINT 'Da luu thanh cong' ELSE
BEGIN
PRINT @Msg
END
Lưu ý
Trang 6Bảng INSERTED là một bảng được phát sinh ra tự động trong các trigger loại INSERT TRIGGER Bảng này dùng để lưu trữ thông tin của một dòng dữ liệu trước khi được đưa vào bảng
dữ liệu của SQL
2.2.2.2 Tạo trigger loại DELETE TRIGGER
Khái niệm
Loại trigger này dùng để kiểm tra sự tồn tại dữ liệu bên các bảng con Tùy theo yêu cầu mà
hệ thống sẽ thông báo hoặc tự động xóa dữ liệu bên các bảng con khi dữ liệu bên bảng cha bị xóa
Cú pháp
CREATE TRIGGER trigger_name ON { table | view }
FOR DELETE
AS
sql_statement
Ví dụ
Với CSDL đã tạo ban đầu, viết một trigger DELETE trên bảng PRODUCTS sao cho khi xóa một ProductID thì trigger phải kiểm tra sự tồn tại của các ProductID có liên quan trên bảng ORDERDETAILS Khi đó, nếu ProductID có tồn tại trong bảng ORDERDETAILS thì thông báo không thể xóa được Ngược lại, thì thông báo đã xóa ProductID đó rồi
CREATE TRIGGER [PRODUCTS_DELETE] ON [dbo].[PRODUCTS]
FOR DELETE
AS
Kiem tra cot ProductID co trong table ORDERDETAILS
IF (SELECT count(*)
FROM ORDERDETAILS c, DELETED d
WHERE c.ProductID = d.ProductID) >0
BEGIN
ROLLBACK TRAN
PRINT 'Khong the xoa'
END
ELSE
PRINT 'Da xoa'
Lưu ý
Bảng DELETED là một bảng được phát sinh ra tự động trong các trigger loại DELETE TRIGGER Bảng này dùng để lưu trữ các dòng dữ liệu sẽ bị xóa
2.2.2.3 Tạo trigger loại UPDATE TRIGGER
Khái niệm
Thực chất hành động UPDATE là sự phối hợp của hai hành động: DELETE và INSERT
Trang 7 Thông thường các hành động bên trong biến cố UPDATE dùng để kiểm tra sự tồn tại của các giá trị khóa ngoại có liên quan
Để kiểm tra giá trị của một cột có bị thay đổi bên trong biến cố UPDATE, sử dụng hàm UPDATE với biến cố như sau:
UPDATE (col_name)
9 Trả về True: khi giá trị trên cột bị thay đổi
9 Trả về False: khi giá trị cột không bị thay đổi
Cú pháp
CREATE TRIGGER trigger_name ON { table | view }
FOR UPDATE
AS
sql_statement
Ví dụ
Với CSDL đã tạo ban đầu, viết một trigger trên bảng CUSTOMERS, biết rằng khi thay đổi CustomerID thì trigger tự động thay đổi trên bảng ORDERS
CREATE TRIGGER [CUSTOMERS_UPDATE] ON [dbo].[CUSTOMERS]
FOR UPDATE
AS
Khai bao bien
DECLARE @Demdong int, @NewCustomerID nchar(5), @OldCustomerID nchar(5) SET @Demdong = @@rowcount
IF @Demdong = 0
RETURN
IF UPDATE (CustomerID)
BEGIN
Kiem tra cot CustomerID co trong table ORDERS
IF EXISTS(SELECT * FROM ORDERS c, DELETED d
WHERE c.CustomerID = d.CustomerID)
BEGIN
Lay gia tri moi CustomerID Æ bien SELECT @NewCustomerID = CustomerID FROM INSERTED
Lay gia tri cu CustomerID Æ bien SELECT @OldCustomerID = CustomerID FROM DELETED
UPDATE ORDERS SET CustomerID = @NewCustomerID WHERE CustomerID = @OldCustomerID
IF @@ERROR <>0
BEGIN
PRINT 'CustomerID ko thay doi'
ROLLBACK TRAN
END
Trang 8ELSE
PRINT 'CustomerID da thay doi'
END
PRINT 'CustomerID da thay doi'
END
2.2.2.4 Tạo trigger tính toán tự động
Với CSDL đã tạo ban đầu, viết một trigger tính toán tự động sử dụng lệnh UPDATE để tính lại giá trị cho cột TotalAmount của bảng ORDERS biết rằng giá trị cột này bằng tổng số lượng * đơn giá của từng hàng hóa trong bảng ORDERDETAILS
Tăng giá trị cột TotalAmount khi thêm một dòng dữ liệu trên bảng ORDERDETAILS
CREATE TRIGGER [ORDERDETAILS_INSERT] ON [dbo].[ORDERDETAILS]
FOR INSERT
AS
Kiem tra tinh hop le cua du lieu trong bang ORDERDETAILS: OrderID ∈ ORDERS.OrderID, ProductID ∈ PRODUCTS.ProductID, Quantity > 0, UnitPrice > 0 Kiem tra cot OrderID trong table ORDERS
DECLARE @OrderID int, @ProductID int, @KT int, @Msg varchar (50)
SET @OrderID=1
IF EXISTS (SELECT *
FROM INSERTED
WHERE OrderID IN
(SELECT OrderID FROM ORDERS))
SET @OrderID=0
Kiem tra cot ProductID trong table PRODUCTS
SET @ProductID=1
IF EXISTS (SELECT *
FROM PRODUCTS n, INSERTED i
WHERE n.ProductID = i.ProductID)
SET @PRODUCTID=0
Kiem tra cot Quantity, UnitPrice trong table ORDERDETAILS
SET @KT=1
IF EXISTS (SELECT *
FROM INSERTED i
WHERE i.Quantity>0 AND i.UnitPrice>0)
SET @KT=0
Xet gia tri cac bien @OrderID, @ProductID, @KT
Neu @OrderID=0, @ProductID=0 va @KT=0 thi luu mau tin moi them
Nguoc lai, thong bao loi vi pham rang buoc khoa ngoai
SET @Msg=
CASE
WHEN @OrderID=0 AND @ProductID=0 AND @KT=0 then 'TC'
Trang 9END
IF @Msg='TC'
PRINT 'Da luu thanh cong'
ELSE
BEGIN
PRINT @Msg
END
Tang gia tri cho cot TotalAmount trong table ORDERS
DECLARE @nOrderID int, @Nsl money, @nDG smallint
SELECT @nOrderID = OrderID, @nSL = Quantity, @nDG = UnitPrice
FROM INSERTED
UPDATE ORDERS
SET TotalAmount = TotalAmount + @Nsl * @Ndg
WHERE OrderID = @nOrderID
Giảm giá trị cột TotalAmount khi một dòng dữ liệu trong bảng ORDERDETAILS bị xóa
CREATE TRIGGER [ORDERDETAILS_DELETE] ON [dbo].[ORDERDETAILS]
FOR DELETE
AS
Khai bao bien
DECLARE @Bien int, @nOrderID int, @nTTG money
SET @Bien = @@rowcount
IF @Bien = 0
RETURN
Giam gia tri cho cot TotalAmount trong table ORDERS
SELECT @nOrderID = OrderID, @nTTG = SUM(Quantity* UnitPrice)
FROM DELETED
GROUP BY OrderID
UPDATE ORDERS
SET TotalAmount = TotalAmount -@Nttg
WHERE OrderID = @nOrderID
Thay đổi giá trị cột TotalAmount khi các cột Quantity, UnitPrice trong bảng ORDERDETAILS bị thay đổi
CREATE TRIGGER [ORDERDETAILS_UPDATE] ON [dbo].[ORDERDETAILS]
FOR UPDATE
AS
Khai bao bien
DECLARE @Bien int, @NewTTG money, @OldTTG money
SET @Bien = @@rowcount
IF @Bien = 0
RETURN
IF UPDATE (Quantity) OR UPDATE (UnitPrice)
BEGIN
Lay gia tri moi Quantity*UnitPrice Æ bien
Trang 10SELECT @NewTTG = Quantity * UnitPrice
FROM INSERTED
Lay gia tri cu Quantity*UnitPrice Æ bien
SELECT @OldTTG = Quantity * UnitPrice
FROM DELETED
Cap nhat gia tri TotalAmount
UPDATE ORDERS
SET TotalAmount = TotalAmount + (@NewTTG-@OldTTG)
IF @@ERROR <>0
BEGIN
PRINT 'TTG ko thay doi'
ROLLBACK TRAN
END
ELSE
PRINT 'TTG da thay doi'
END
2.3 Sửa trigger
1 Chọn server group Æ chọn server
2 Chọn Databases Æ chọn database chứa table có định nghĩa trigger Æ click Tables
3 Trong khung trình bày các đối tượng table có định nghĩa trigger của database Æ click phải
chuột tại tên table muốn sửa trigger Æ chọn All Tasks Æ chọn Manage Triggers …
4 Tại mục Name, chọn tên của trigger
5 Thay đổi nội dung của trigger in mục Text
6 Click Check Syntax để kiểm tra lỗi cú pháp
Trang 11
2.4 Xóa trigger
1 Chọn server group Æ chọn server
2 Chọn Databases Æ chọn database chứa table có định nghĩa trigger Æ click Tables
3 Trong khung trình bày các đối tượng table có định nghĩa trigger của database Æ click phải
chuột tại tên table muốn xóa trigger Æ chọn All Tasks Æ chọn Manage Triggers …
4 Tại mục Name, chọn tên trigger muốn xóa
5 Click Delete
Trang 126 Xác nhận xóa
2.5 Bài tập
Lưu ý: thứ tự ưu tiên khi kiểm tra ràng buộc dữ liệu thì các CONSTRAINT sẽ được kiểm tra
trước TRIGGER Do đó, khi muốn các TRIGGER được thực hiện chúng ta phải tạm thời tắt các hoạt động của CONSTRAINT bằng cú pháp của lệnh sau:
ALTER TABLE ten_bang
NOCHECK CONSTRAINT ALL
1 Tạo trigger xóa dữ liệu tự động bên bảng con khi dữ liệu bên bảng cha bị xóa
a Tạm thời tắt đi các CONSTRAINT trên bảng ORDERDETAILS
b Viết 1 trigger DELETE trên bảng ORDERS sao cho khi xóa 1 OrderID thì trigger sẽ tự động xóa các OrderID có liên quan bên bảng ORDERDETAILS Khi đó thông báo ra màn hình bằng lệnh PRINT cho người dùng biết đã xóa bao nhiêu dòng trong bảng ORDERDETAILS
c Sau đó xóa thử OrderID 10249 trong bảng ORDERS và xem kết quả thực hiện
2 Tạo trigger kiểm tra sự tồn tại dữ liệu bên bảng con khi dữ liệu bên bảng cha bị xóa
a Viết 1 trigger DELETE trên bảng PRODUCTS sao cho khi xóa 1 ProductID thì trigger phải kiểm tra sự tồn tại của các ProductID có liên quan bên bảng ORDERDETAILS Khi
đó nếu ProductID có tồn tại trong bảng ORDERDETAILS thì thông báo không thể xóa được Ngược lại thì thông báo đã xóa ProductID đó rồi
b Sau đó lần lượt xóa các ProductID sau: 25 và 70 và xem kết quả thực hiện
3 Tạo trigger kiểm tra sự tồn tại các khóa ngoại bên bảng cha khi dữ liệu bên bảng con được thêm vào
a Tạm thời tắt đi các CONSTRAINT trên bảng ORDERS
b Viết 1 trigger INSERT trên bảng ORDERS sao cho khi thêm 1 dòng dữ liệu vào bảng ORDERS phải kiểm tra các cột khóa ngoại: cột CustomerID trong bảng CUSTOMERS,
Trang 13EmployeeID trong bảng EMPLOYEES
c Viết 1 trigger INSERT trên bảng ORDERDETAILS sao cho khi thêm 1 dòng dữ liệu vào bảng ORDERDETAILS phải kiểm tra các cột khóa ngoại: cột OrderID trong bảng ORDERS, ProductID trong bảng PRODUCTS
4 Tạo trigger tính toán tự động
a Trong bảng PRODUCTS chèn thêm 1 cột có tên là Total_Quantity với kiểu là INT
b Sử dụng lệnh UPDATE để tính lại giá trị cho cột Total_Quantity biết rằng giá trị cho cột này bằng tổng số lượng của từng hàng hóa trong bảng ORDERDETAILS
c Viết trigger INSERT trên bảng ORDERDETAILS dùng để tăng giá trị tự động cho cột Total_Quantity trong bảng PRODUCTS sau khi một dòng dữ liệu hợp lệ đã được lưu vào trong bảng ORDERDETAILS (có thể quay lại trigger của câu 3.c để viết tiếp mà không cần tạo mới 1 trigger)
d Viết trigger DELETE trên bảng ORDERDETAILS dùng để giảm giá trị tự động cho cột Total_Quantity trong bảng PRODUCTS sau khi một dòng dữ liệu đã bị xóa trong bảng ORDERDETAILS
e Viết trigger UPDATE trên bảng ORDERDETAILS dùng để cập nhật giá trị tự động cho cột Total_Quantity trong bảng PRODUCTS sau khi một dòng dữ liệu đã bị thay đổi trong bảng ORDER DETAILS
f Trong bảng ORDERS có cột tên là TotalAmount Viết các trigger cần thiết để giá trị cột này được cập nhật tự động Biết rằng giá trị cột này chính là tổng trị giá của một OrderID