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..
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.
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
Cannot use text, ntext, or image columns in the 'inserted' and 'deleted' tables.
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:
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. Ntext is deprecated anyhow and should not be used going forward
Like said in the other answer ntext
, along with text
and image
are deprecated datatypes which triggers can't really work with. 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.
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.
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. 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:
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.