2013-06-27 78 views
0

我需要一些数据库触发器的帮助,但我无法正常工作。披露:我不是一个DBA,并且不要求任何专业知识,但我一直在负责完成这一操作..SQL Server 2008触发器错误

也就是说,这里的问题陈述:

我有一个数据库我们想跟踪更新/插入/删除的几个表。触发器应该捕捉某些列的“之前”和“之后”值,同时附带一些附加信息(如下所述)并将它们添加到​​表中。

我已经把我认为应该工作基础上的教程和其他信息可在各种网站,但无论我做什么,当我尝试创建触发器它总是抛出一个错误:

Msg 311, Level 16, State 1, Procedure tr_taskconstructs_U, Line 38
Cannot use text, ntext, or image columns in the 'inserted' and 'deleted' tables.

为我申请的触发器表中的列布局很简单:

ResourceID (PK, nvarchar(38)) 
AML (ntext, null) 

我要赶更改AML列并插入转变为一个表,如下所示:

id (int, not null), 
ResourceID (nvarchar(38)), 
TableName (nvarchar(50)), 
DateTime (datetime), 
Type (varchar(20)), 
Before (ntext), 
After (ntext) 

我的代码如下:

CREATE TRIGGER tr_taskconstructs_U ON taskconstructs AFTER UPDATE 
AS 
BEGIN 

SET NOCOUNT ON; 

    DECLARE @before nvarchar(max), 
     @after nvarchar(max), 
     @resource nvarchar(50) 

IF UPDATE(AML) 
BEGIN 
    SELECT @before = d.AML, 
      @after = i.AML, 
      @resource = d.ResourceID 
    FROM inserted i 
     INNER JOIN deleted d on d.ResourceID = i.ResourceID 

    INSERT INTO versioncontrol 
    VALUES (@resource, 'taskconstructs', GetDate(), 'Update', @before, @after) 

END 

END 
GO 

它总是失败,上面提到的错误。我试着改变变量的数据类型等,结果相同。我试过评论几乎所有的东西,它也有同样的错误。我显然缺少一些东西,但我无法弄清楚什么。

任何帮助,将不胜感激。

回答

1

就像在其他回答ntext中说的,以及textimage是不赞成使用的数据类型,这些触发器不能真正起作用。他们将被删除的SQL Server的未来版本,所以你最好的解决办法是将它们分别改为NVARCHAR(MAX)VARCHAR(MAX)VARBINARY(MAX)

http://msdn.microsoft.com/en-us/library/ms189799.aspx

但是,如果这不是在此刻为你的可能性 - INSTEAD OF触发与他们合作,所以你可以尝试拦截更新和触发做他们,尽显你的日志表的过程。

但是,之前我给你举例说,你在你现有的触发我必须指出一个很大的错误 - 你已经写了上单列从INSERTED只能查询这是不好的UPDATE能通常更新时间超过1行。即使你的应用程序没有被设计为允许它,你也不应该写触发器,因为它总是会是单行的。

所以,你的触发器应该是这个样子的: (应该是这样的,如果/当你改变了该列)现在

CREATE TRIGGER tr_taskconstructs_U ON taskconstructs AFTER UPDATE 
AS 
BEGIN 

SET NOCOUNT ON; 

IF UPDATE(AML) 
BEGIN 

    INSERT INTO versioncontrol 
    SELECT ResourceID, 'taskconstructs', GetDate(), 'Update'. d.AML, i.AML 
    FROM inserted i 
    INNER JOIN deleted d on d.ResourceID = i.ResourceID 

END 

END 
GO 

,为INSTEAD OF TRIGGER:

CREATE TRIGGER tr_taskconstructs_U ON taskconstructs INSTEAD OF UPDATE 
AS 
BEGIN 

    --insert log 
    INSERT INTO versioncontrol 
    SELECT i.ResourceID, 'taskconstructs', GetDate(), 'Update', d.AML, i.AML 
    FROM inserted i 
    INNER JOIN taskconstructs d on d.ResourceID = i.ResourceID 

    --update actual data 
    UPDATE t 
    SET t.AML = i.AML 
    from taskconstructs t 
    INNER JOIN INSERTED i ON i.ResourceID = t.ResourceID 

END 
GO 

SQLFiddle DEMO

+0

@Nenand - 您对INSTEAD OF UPDATE的解决方案非常完美。由于该应用程序是商业应用程序,因此我将运行此应用程序,并且我不知道如何更改他们的某个系统表会影响应用程序。同时也非常感谢你在多行上的发现......你让我看起来像英雄。 :) – user2093445

+0

@ user2093445 YW! :)至于改变列类型 - 虽然我不会建议你做任何事情,而不先咨询任何负责非生产环境中的应用程序和测试的人。 - 我认为从'ntext'切换到'nvarchar(max)'应该没有任何问题,而不需要改变应用程序。 http://www.sqlfiddle.com/#!6/2d9b1/2 –

5

更改表以改为使用nvarchar(max)数据类型。 Ntext已被弃用,不应该继续使用

+0

感谢SQLMenace - 我已经更新了versioncontrol表中的列使用varchar或nvarchar,但我仍然得到相同的错误。 – user2093445

+1

@ user2093445您需要更改'taskconstructs'表。触发器无法监控'ntext'列上的更改 –

+0

啊,我明白了。我在版本控制表上更改了它。我不确定是否可以更改任务构造表,因为该应用程序是商业应用程序,我无法更改源代码。如果我无法更改源表格,是否有任何选项? – user2093445