0

我需要一些关于我无法工作的数据库触发器的帮助。披露:我不是 DBA,也没有任何专业知识,但我的任务是完成这项工作。

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

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

我已经根据教程和各种网站上提供的其他信息汇总了我认为应该工作的内容,但是无论我在尝试创建触发器时做什么,它总是会引发错误:

消息 311,级别 16,状态 1,过程 tr_taskconstructs_U,第 38 行
不能在“已插入”和“已删除”表中使用 text、ntext 或 image 列。

我应用触发器的表的列布局非常简单:

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

它总是因上述错误而失败。我尝试更改变量等的数据类型,结果相同。我试过注释掉几乎所有的东西,它也有同样的错误。我显然错过了一些东西,但无法弄清楚是什么。

任何帮助,将不胜感激。

4

2 回答 2

5

更改表以改用 nvarchar(max) 数据类型。Ntext 无论如何都已被弃用,不应继续使用

于 2013-06-27T18:29:06.753 回答
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触发器:

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 演示

于 2013-06-27T19:17:04.750 回答