Tôi thích các giải pháp là "khoa học máy tính thanh lịch." Giải pháp của tôi ở đây đánh vào các giả danh [đã chèn] và [đã xóa] mỗi lần để lấy trạng thái của chúng và đặt kết quả vào một biến được ánh xạ bit. Sau đó, mỗi sự kết hợp có thể của INSERT, UPDATE và DELETE có thể dễ dàng được kiểm tra trong suốt quá trình kích hoạt với các đánh giá nhị phân hiệu quả (ngoại trừ kết hợp INSERT hoặc DELETE không có khả năng).
Nó đưa ra giả định rằng không có vấn đề gì với câu lệnh DML nếu không có hàng nào được sửa đổi (điều này sẽ đáp ứng phần lớn các trường hợp). Vì vậy, trong khi nó không hoàn chỉnh như giải pháp của Roman Pekar, thì nó hiệu quả hơn.
Với cách tiếp cận này, chúng tôi có khả năng một trình kích hoạt "CHO XÁC NHẬN, CẬP NHẬT, XÓA" trên mỗi bảng, cho chúng tôi A) kiểm soát hoàn toàn trật tự hành động và b) thực hiện một mã cho mỗi hành động áp dụng nhiều hành động. (Rõ ràng, mọi mô hình triển khai đều có ưu và nhược điểm; bạn sẽ cần đánh giá riêng các hệ thống của mình để biết những gì thực sự hoạt động tốt nhất.)
Lưu ý rằng các câu lệnh "tồn tại (chọn * từ« được chèn / xóa ») rất hiệu quả do không có quyền truy cập đĩa ( https://social.msdn.microsoft.com/Forums/en-US/01744422-23fe-42f6 -9ab0-a255cdf2904a ).
use tempdb
;
create table dbo.TrigAction (asdf int)
;
GO
create trigger dbo.TrigActionTrig
on dbo.TrigAction
for INSERT, UPDATE, DELETE
as
declare @Action tinyint
;
-- Create bit map in @Action using bitwise OR "|"
set @Action = (-- 1: INSERT, 2: DELETE, 3: UPDATE, 0: No Rows Modified
(select case when exists (select * from inserted) then 1 else 0 end)
| (select case when exists (select * from deleted ) then 2 else 0 end))
;
-- 21 <- Binary bit values
-- 00 -> No Rows Modified
-- 01 -> INSERT -- INSERT and UPDATE have the 1 bit set
-- 11 -> UPDATE <
-- 10 -> DELETE -- DELETE and UPDATE have the 2 bit set
raiserror(N'@Action = %d', 10, 1, @Action) with nowait
;
if (@Action = 0) raiserror(N'No Data Modified.', 10, 1) with nowait
;
-- do things for INSERT only
if (@Action = 1) raiserror(N'Only for INSERT.', 10, 1) with nowait
;
-- do things for UPDATE only
if (@Action = 3) raiserror(N'Only for UPDATE.', 10, 1) with nowait
;
-- do things for DELETE only
if (@Action = 2) raiserror(N'Only for DELETE.', 10, 1) with nowait
;
-- do things for INSERT or UPDATE
if (@Action & 1 = 1) raiserror(N'For INSERT or UPDATE.', 10, 1) with nowait
;
-- do things for UPDATE or DELETE
if (@Action & 2 = 2) raiserror(N'For UPDATE or DELETE.', 10, 1) with nowait
;
-- do things for INSERT or DELETE (unlikely)
if (@Action in (1,2)) raiserror(N'For INSERT or DELETE.', 10, 1) with nowait
-- if already "return" on @Action = 0, then use @Action < 3 for INSERT or DELETE
;
GO
set nocount on;
raiserror(N'
INSERT 0...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 0 object_id from sys.objects;
raiserror(N'
INSERT 3...', 10, 1) with nowait;
insert dbo.TrigAction (asdf) select top 3 object_id from sys.objects;
raiserror(N'
UPDATE 0...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t where asdf <> asdf;
raiserror(N'
UPDATE 3...', 10, 1) with nowait;
update t set asdf = asdf /1 from dbo.TrigAction t;
raiserror(N'
DELETE 0...', 10, 1) with nowait;
delete t from dbo.TrigAction t where asdf < 0;
raiserror(N'
DELETE 3...', 10, 1) with nowait;
delete t from dbo.TrigAction t;
GO
drop table dbo.TrigAction
;
GO