设为首页 加入收藏

TOP

SqlServerINSTEADOFUPDATE视图触发器问题(一)
2015-07-24 10:15:54 来源: 作者: 【 】 浏览:2
Tags:SqlServerINSTEADOFUPDATE 触发器 问题

源于系统中的 INSTEAD OF UPDATE 视图触发器关联表更新时,发生了错误如下:

消息 414,级别 16,状态 1,第 1 行
不允许使用 UPDATE,因为该语句会更新视图 "VTestTab",而该视图参与联接并且有一个 INSTEAD OF UPDATE 触发器。

于是测试该触发器的执行原理是什么!~

说明:

视图只能被 INSTEAD OF 触发器引用,每个 INSERT、UPDATE 或 DELETE 语句最多可定义一个 INSTEAD OF 触发器
INSTEAD OF 触发器不可以用于使用 WITH CHECK OPTION 的可更新视图,否则 SQL Server 将引发错误

创建测试环境:

?

--	DROP TABLE [TestTab]	--	TRUNCATE TABLE [TestTab]
--	创建表
CREATE TABLE [dbo].[TestTab](
	[id] [int] NOT NULL,
	[name] [varchar](50) NOT NULL,
	[insertDate] [datetime] NOT NULL,
	[value] [numeric](14, 4) NULL,
	[info] [varchar](20) NULL,
	CONSTRAINT [PK_TestTab] PRIMARY KEY CLUSTERED ([id] ASC)
) ON [PRIMARY]
GO

--	创建视图
CREATE VIEW [dbo].[VTestTab]
AS
SELECT [id] ,[name],[insertDate],[value],[info]
FROM [dbo].[TestTab]
GO

--	创建视图更新触发器(主要为这个引发的问题!)
CREATE TRIGGER [dbo].[tgr_VTestTab_update]        
ON [dbo].[VTestTab] INSTEAD OF UPDATE        
AS  
UPDATE [VTestTab] SET 
[name] = T2.[name],
[insertDate] = T2.[insertDate],
[value] = T2.[value],
[info] = T2.[info]
FROM [VTestTab] AS t1, inserted AS t2 WHERE t1.id = t2.id
GO

--	插入数据到视图
INSERT INTO [VTestTab]
SELECT 1,'kk',GETDATE(),0,''
UNION ALL
SELECT 2,'JJ',GETDATE(),5,'HH'
UNION ALL
SELECT 3,'SS',GETDATE(),10,''
UNION ALL
SELECT 4,'MM',GETDATE(),0,NULL
UNION ALL
SELECT 5,'YY',GETDATE(),11,''
GO


--	创建另一个表(或 实体表),稍后用于关联更新
SELECT * INTO #TestTab FROM [VTestTab] 


--	当前表、视图、临时表
SELECT [id],[name],[insertDate],[value],[info] FROM [dbo].[TestTab]
SELECT * FROM [dbo].[VTestTab]
SELECT * FROM [dbo].#TestTab

现在对单个视图更新:

?

?

--	对视图更新
UPDATE [VTestTab] SET [value]=100 WHERE id = 1
\

?

对单个视图更新,结果正常,但是执行了2次!~执行计划可以看到!~

是不是真的执行了两次?!

官方说明为:
如果为视图定义的 INSTEAD OF 触发器对视图执行了一条通常会再次触发 INSTEAD OF 触发器的语句,该语句不会被递归调用,而是将该语句解析为对视图所依存的基本表进行的修改,再次触发的操作就像该视图没有 INSTEAD OF 触发器一样。由 UPDATE 更改的列必须解析到一个基表。对基表的每次修改都将应用约束并触发为该表定义的 AFTER 触发器。

?

为了查看这两次执行到底哪次是有用的,现在使用 UPDATE(尝试更新) 和 COLUMNS_UPDATED (实际更新)来跟踪查看。

创建2张表,跟踪列更改情况。尝试更新表(attemptOperation)和实际更新表(factOperation):

?

--	DROP TABLE attemptOperation,factOperation
CREATE TABLE attemptOperation(Col VARCHAR(20),isUpdate BIT)
CREATE TABLE factOperation(Col VARCHAR(20),isUpdate BIT)

更改视图,将对列的更新情况记录到表中,但不触发更新:

?

?

ALTER TRIGGER [dbo].[tgr_VTestTab_update]        
ON [dbo].[VTestTab] INSTEAD OF UPDATE        
AS 
BEGIN
IF(UPDATE([id]))
	INSERT INTO attemptOperation(Col,isUpdate) SELECT 'id',1
IF(UPDATE([name]))
	INSERT INTO attemptOperation(Col,isUpdate) SELECT 'name',1
IF(UPDATE([insertDate]))
	INSERT INTO attemptOperation(Col,isUpdate) SELECT 'insertDate',1
IF(UPDATE([value]))
	INSERT INTO attemptOperation(Col,isUpdate) SELECT 'value',1
IF(UPDATE([info]))
	INSERT INTO attemptOperation(Col,isUpdate) SELECT 'info',1

IF(SUBSTRING(COLUMNS_UPDATED(),1,1)&1=1)
	INSERT INTO factOperation(Col,isUpdate) SELECT 'id',1
IF(SUBSTRING(COLUMNS_UPDATED(),1,1)&2=2)
	INSERT INTO factOperation(Col,isUpdate) SELECT 'name',1
IF(SUBSTRING(COLUMNS_UPDATED(),1,1)&4=4)
	INSERT INTO factOperation(Col,isUpdate) SELECT 'insertDate',1
IF(SUBSTRING(COLUMNS_UPDATED(),1,1)&8=8)
	INSERT INTO factOperation(Col,isUpdate) SELECT 'value',1
IF(SUBSTRING(COLUMNS_UPDATED(),1,1)&16=16)
	INSERT INTO factOperation(Col,isUpdate) SELECT 'info',1
END
GO

再次对视
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇SQLite应用详解 下一篇SQL语言和T-SQL语言简介

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·如何从内核协议栈到 (2025-12-27 03:19:09)
·什么是网络协议?有哪 (2025-12-27 03:19:06)
·TCP/ IP协议有哪些 (2025-12-27 03:19:03)
·怎样用 Python 写一 (2025-12-27 02:49:19)
·如何学习python数据 (2025-12-27 02:49:16)