[SQL]使用trigger

[SQL]使用trigger

練習一下

-- 資料來源:德瑞克老師的上課筆記+自行修改
-- 使用 Trigger 紀錄資料表的新增、修改、刪除的行為 
-- http://www.dotblogs.com.tw/jameswu/archive/2009/07/23/9643.aspx
USE ProductDB
GO 

-- 從正式表格隨機選取員工編號後新增測試資料
-- 建立測試表格
IF  EXISTS
(SELECT *
 FROM
	 sys.objects
 WHERE
	 object_id = object_id(N'[dbo].[EMPLOYEE_TEST_DATA]')
	 AND type IN (N'U')) DROP TABLE [dbo].[EMPLOYEE_TEST_DATA]
GO
CREATE TABLE [dbo].[EMPLOYEE_TEST_DATA]
(
[STAFF] [nvarchar](6)PRIMARY KEY,
[NOTE][nvarchar](30)DEFAULT ('這是林大貓的測試資料'),
[CEATETIME][datetime] DEFAULT getdate()
);
GO

IF  EXISTS
(SELECT *
 FROM
	 sys.objects
 WHERE
	 object_id = object_id(N'[dbo].[EMPLOYEE_TEST_DATA_LOG]')
	 AND type IN (N'U')) DROP TABLE [dbo].[EMPLOYEE_TEST_DATA_LOG]
GO
CREATE TABLE [dbo].[EMPLOYEE_TEST_DATA_LOG]
(
	[ACTION][nvarchar](10),
	[STAFF] [nvarchar](6),
	[NOTEBEFORE][nvarchar](30),
	[NOTEAFTER][nvarchar](30),	
	[RECORDDATE][datetime] DEFAULT getdate()
);
GO

-- 檢查測試表格
SELECT *
FROM
	dbo.EMPLOYEE_TEST_DATA
SELECT *
FROM
	dbo.EMPLOYEE_TEST_DATA_LOG

-- 隨機選取十筆資料當作測試資料
INSERT [dbo].[EMPLOYEE_TEST_DATA] (STAFF)
SELECT TOP 10 STAFF
FROM
	dbo.EMPLOYEE
ORDER BY
	newid()
GO

-- 寫入固定資料
INSERT [dbo].[EMPLOYEE_TEST_DATA] (STAFF)
SELECT '123456'

-- 查詢測試表格資料
SELECT *
FROM
	dbo.EMPLOYEE_TEST_DATA

-- trigger(AFTER)
-- 功能:當刪除多筆資料時會發出訊息並且Rollback
IF exists
(SELECT name
 FROM
	 sys.triggers
 WHERE
	 name = 'tri_employee_test_data_del') DROP TRIGGER dbo.tri_employee_test_data_del
GO	 
create trigger tri_employee_test_data_del
on dbo.EMPLOYEE_TEST_DATA
after delete	
as
declare @rowcount int
SELECT @rowcount = count(*)
FROM
	DELETED;
IF(@rowcount >1)
	begin
SELECT '一次只能刪除一筆資料!您的請求將退回!';
		ROLLBACK TRANSACTION
	end
GO

-- 功能:每次僅能更新一筆資料列
IF exists
(SELECT name
 FROM
	 sys.triggers
 WHERE
	 name = 'tri_employee_test_data_update') DROP TRIGGER dbo.tri_employee_test_data_update
GO	
CREATE TRIGGER tri_employee_test_data_update 
	ON dbo.EMPLOYEE_TEST_DATA
	AFTER UPDATE
AS
IF @@ROWCOUNT > 1
BEGIN
   RAISERROR(N'每次僅能更新一筆資料',10, 1)
   ROLLBACK TRANSACTION
END
GO

-- 功能:當修改資料時同時寫到log
IF exists
(SELECT name
 FROM
	 sys.triggers
 WHERE
	 name = 'tri_employee_test_data_log') DROP TRIGGER dbo.tri_employee_test_data_log
GO	 
create trigger tri_employee_test_data_log
on dbo.EMPLOYEE_TEST_DATA
after insert,update,delete
as
declare @type nvarchar(10);
IF EXISTS
(SELECT 1
 FROM
	 inserted) AND NOT EXISTS (SELECT 1
							   FROM
								   deleted) 
BEGIN
SELECT @type = N'新增';
INSERT INTO dbo.EMPLOYEE_TEST_DATA_LOG ([ACTION]
									  , [STAFF]
									  , [NOTEBEFORE]
									  , [NOTEAFTER])
SELECT @type
	 , STAFF
	 , NULL
	 , NOTE
FROM
	INSERTED;
END								   
IF EXISTS
(SELECT 1
 FROM
	 inserted) AND EXISTS (SELECT 1
						   FROM
							   deleted) 
BEGIN
SELECT @type = N'修改';
INSERT INTO dbo.EMPLOYEE_TEST_DATA_LOG ([ACTION]
									  , [STAFF]
									  , [NOTEBEFORE]
									  , [NOTEAFTER])
SELECT @type
	 , a.STAFF
	 , b.NOTE
	 , a.NOTE
FROM
	INSERTED a
	INNER JOIN DELETED b
		ON a.STAFF = b.STAFF;
END							   
IF NOT EXISTS
(SELECT 1
 FROM
	 inserted) AND EXISTS (SELECT 1
						   FROM
							   deleted) 
BEGIN
SELECT @type = N'刪除';
INSERT INTO dbo.EMPLOYEE_TEST_DATA_LOG ([ACTION]
									  , [STAFF]
									  , [NOTEBEFORE]
									  , [NOTEAFTER])
SELECT @type
	 , STAFF
	 , NOTE
	 , NULL
FROM
	DELETED 	
END				   
GO

-- trigger(INSTEAD of)
-- 禁止使用者修改刪除log
IF exists
(SELECT name
 FROM
	 sys.triggers
 WHERE
	 name = 'tri_employee_test_data_log_DisableModify') DROP TRIGGER dbo.tri_employee_test_data_log_DisableModify
GO	 
create trigger tri_employee_test_data_log_DisableModify
on dbo.EMPLOYEE_TEST_DATA_LOG
instead of update,delete
as
 RAISERROR(N'不可以對log紀錄進行修改刪除!',10, 1); 
GO


-- 檢查tringger是否建立
SELECT object_name(t.parent_id) N'資料表'
	 , t.name N'觸發程序名稱'
	 , parent_class_desc N'觸發程序父類別的描述'
	 , t.type_desc N'物件類型的描述'
	 , tEV.type_desc '引發觸發程序的每個事件'
	 , is_instead_of_trigger N'是否為 INSTEAD OF 觸發程序'
FROM
	sys.triggers t
	INNER JOIN sys.trigger_events tEV
		ON t.object_id = tEV.object_id
GO

-- 測試trigger(會出現失敗訊息)
DELETE
FROM
	dbo.EMPLOYEE_TEST_DATA

UPDATE dbo.EMPLOYEE_TEST_DATA
SET
	NOTE = N'測試資料'
GO

-- 測試trigger(會出現成功訊息)
INSERT INTO dbo.EMPLOYEE_TEST_DATA (STAFF)
VALUES
	('999999');

UPDATE dbo.EMPLOYEE_TEST_DATA
SET
	NOTE = N'可修改的測試資料'
WHERE
	STAFF = '999999'

DELETE
FROM
	dbo.EMPLOYEE_TEST_DATA
WHERE
	STAFF = '999999'
GO

-- 測試trigger(會出現失敗訊息)(INSTEAD OF)
DELETE
FROM
	dbo.EMPLOYEE_TEST_DATA_LOG

UPDATE dbo.EMPLOYEE_TEST_DATA_LOG
SET
	NOTEAFTER = NULL
GO

-- 查詢測試表格資料
SELECT *
FROM
	dbo.EMPLOYEE_TEST_DATA
SELECT *
FROM
	dbo.EMPLOYEE_TEST_DATA_LOG

-- 刪除測試資料
DROP TABLE dbo.EMPLOYEE_TEST_DATA
DROP TABLE dbo.EMPLOYEE_TEST_DATA_LOG
GO