简体   繁体   English

SQL Server 2008触发错误

[英]SQL Server 2008 Trigger Errors

I need some help with a database trigger that I just can't get working. 我需要一些我无法使用的数据库触发器的帮助。 Disclosure : I'm not a DBA and don't claim any expertise, but I've been tasked with getting this done.. 披露:我不是DBA,也不要求任何专业知识,但是我的任务是完成这项工作。

That said, here is the problem statement: 也就是说,这是问题陈述:

I have a database with a few tables that we want to track updates/inserts/deletes on. 我有一个包含一些表的数据库,我们希望跟踪这些表的更新/插入/删除。 The trigger should catch the "before" and the "after" values of some columns, take both along with some additional information (mentioned below) and add them to a versioncontrol table. 触发器应捕获某些列的“ before”和“ after”值,并结合一些附加信息(如下所述)并将它们添加到versioncontrol表中。

I've put together what I think should work based on tutorial and other information available on various sites, but no matter what I do when I try to create the trigger it always throws an error: 我已经根据教程和其他网站上的其他信息整理了我认为应该起作用的内容,但是无论如何尝试创建触发器,它总是会引发错误:

Msg 311, Level 16, State 1, Procedure tr_taskconstructs_U, Line 38 消息311,级别16,状态1,过程tr_taskconstructs_U,第38行
Cannot use text, ntext, or image columns in the 'inserted' and 'deleted' tables. 不能在“已插入”和“已删除”表中使用text,ntext或image列。

The column layout for the table I'm applying the trigger to is very simple: 我将触发器应用到的表的列布局非常简单:

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

I want to catch changes to the AML column and insert the changes into a table, as follows: 我想捕获对AML列的更改,并将更改插入到表中,如下所示:

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

My code is as follows: 我的代码如下:

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

It always fails with the error mentioned above. 它总是会因上述错误而失败。 I tried changing the datatypes of the variables, etc, with the same result. 我尝试更改变量等的数据类型,但结果相同。 I've tried commenting out almost everything and it also has the same error. 我尝试注释掉几乎所有内容,并且也有相同的错误。 I'm obviously missing something, but am not able to figure out what. 我显然缺少了一些东西,但无法弄清楚是什么。

Any help would be appreciated. 任何帮助,将不胜感激。

change the table to use the nvarchar(max) datatype instead. 更改表以使用nvarchar(max)数据类型代替。 Ntext is deprecated anyhow and should not be used going forward 无论如何,Ntext已被弃用,今后不应该使用

Like said in the other answer ntext , along with text and image are deprecated datatypes which triggers can't really work with. 就像在另一个答案中所说的, ntexttextimage都是已过时的数据类型,触发器无法真正使用它。 They will be removed for future versions of SQL Server so your best solution would be to change them to NVARCHAR(MAX) , VARCHAR(MAX) or VARBINARY(MAX) respectively. 对于将来的SQL Server版本,将删除它们,因此最好的解决方案是将它们分别更改为NVARCHAR(MAX)VARCHAR(MAX)VARBINARY(MAX)

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

However, if that's not a possibility for you at the moment - INSTEAD OF trigger can work with them so you can try to intercept the updates and do them from trigger, filling your log table in the process. 但是,如果目前您不知道这种情况INSTEAD OF触发器可以与它们配合使用,那么您可以尝试拦截更新并从触发器中进行更新,从而在此过程中填写日志表。

But, before I show you example of that, I must point out a big mistake you have in your existing trigger - You have wrote the query that works only on single row from INSERTED which is not good as UPDATE can often update more then 1 row at the time. 但是,在向我展示该示例之前,我必须指出您现有触发器中存在的一个大错误 -您编写的查询仅对INSERTED中的单行有效,这不好,因为UPDATE经常可以更新多于1行当时。 Even if your app is not designed to allow it, you should never write trigger asuming it is always going to be single row. 即使您的应用程序没有被设计为允许它使用,也不要编写触发器,因为它总是单行的。

So your trigger should have looked like this: (and should look like this if/after you change that column) 因此您的触发器应该看起来像这样:(并且如果更改该列,则应该看起来像这样)

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

Now, for the INSTEAD OF TRIGGER: 现在,对于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 SQLFiddle演示

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM