Below is a trigger I’ve created for a table in a SQL database (We are running SQL Server 2008). We are going to be doing updates, inserts, and deletes in bulk so we created this trigger and a “storage” table (TransactionLog) to capture all the activity. So far, this trigger works perfectly for inserts and updates. All the records wind up in the “storage” table with all appropriate values.
However, the problem occurs when we try to delete anything more than one record. The only record this trigger captures and sends to the “storage” table is the last record deleted. All others get lost.
CREATE TRIGGER [dbo].[trg_Agent_ALL]
ON [dbo].[Agent]
FOR INSERT, UPDATE, DELETE
AS
BEGIN
--TransactionLog variables
DECLARE @tableName char(25) = 'Agent'
DECLARE @transDate datetime
DECLARE @lastChangeOperator char(6)
DECLARE @tableString char(255)
DECLARE @action char(1) = 'I'
DECLARE @userId char(25)
--Trigger table variables
DECLARE @sNumber char(10)
DECLARE @controlId char(3)
DECLARE @entityType char(1)
DECLARE @firstName nvarchar(50)
DECLARE @lastName nvarchar(50)
DECLARE @suffix nvarchar(10)
DECLARE @corpName nvarchar(100)
IF EXISTS (SELECT * FROM deleted)
BEGIN
SET @action =
CASE
WHEN EXISTS (SELECT * FROM inserted) THEN 'U'
ELSE 'D'
END
END
IF @action = 'D'
BEGIN
SELECT @sNumber = sNumber, @lastChangeOperator = LastChangeOperator, @transDate = LastChangeDate, @entityType = EntityType,
@firstName = FirstName, @lastName = LastName, @suffix = NameSuffix, @corpName = CorporateName, @controlId = ControlId
FROM deleted
IF @firstName IS NULL SET @firstName = 'NULL'
IF @lastName IS NULL SET @lastName = 'NULL'
IF @suffix IS NULL SET @suffix = 'NULL'
IF @corpName IS NULL SET @corpName = 'NULL'
IF @controlId IS NULL SET @controlId = 'NULL'
SET @tableString = 'sNum:' + @sNumber + ' ' + 'EntType:' + @entityType + ' ' + 'Fname:' + @firstName + ' ' + 'Lname:' + @lastname + ' ' + 'suf:' + @suffix +
' ' + 'crpName:' + @corpName + ' ' + 'crlId:' + @controlId
END
ELSE
BEGIN
SELECT @sNumber = SymetraNumber, @lastChangeOperator = LastChangeOperator, @transDate = LastChangeDate, @entityType = EntityType,
@firstName = FirstName, @lastName = LastName, @suffix = NameSuffix, @corpName = CorporateName, @controlId = ControlId
FROM inserted
IF @firstName IS NULL SET @firstName = 'NULL'
IF @lastName IS NULL SET @lastName = 'NULL'
IF @suffix IS NULL SET @suffix = 'NULL'
IF @corpName IS NULL SET @corpName = 'NULL'
IF @controlId IS NULL SET @controlId = 'NULL'
SET @tableString = 'sNum:' + @sNumber + ' ' + 'EntType:' + @entityType + ' ' + 'Fname:' + @firstName + ' ' + 'Lname:' + @lastname + ' ' + 'suf:' + @suffix +
' ' + 'crpName:' + @corpName + 'crlId:' + @controlId
END
INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
VALUES (@transDate, 'Op', @tableName, @action, @tableString, @lastChangeOperator)
END
Based on the comments below I’ve altered the SQL code in the delete section. The hard-coded values seem to be working, however the main reason I placed them in there just to show those are the values I need for those specific columns. I have variables set with these values in the code above (see the DECLARE statements). This, however, is giving me the following error message:
Conversion failed when converting the varchar value 'P' to data type int.
This error is coming off of the EntityType attribute in the inner SELECT statement. What confuses me is that this column has a data type set to char(1), and the TableString column (the destination of the concatenated values) has a data type of nvarchar(255). No clue where the “int” is coming from…
IF @action = 'D'
BEGIN
INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
SELECT LastChangeDate, 'Op', 'Agent', 'D',
(SELECT CAST(CAST(sNumber as nvarchar) + ' ' + EntityType + ' ' + ISNULL(FirstName, ' ') + ' ' + ISNULL(LastName, ' ') + ' ' + ISNULL(NameSuffix, ' ') + ' ' +
ISNULL(CorporateName, ' ' ) + ' ' + ISNULL(CAST(ControlId as nvarchar), ' ') AS nvarchar) as TableString
FROM deleted), LastChangeOperator
FROM deleted
END
ELSE
EDIT
By casting the sNumber and controlId fields to nvarchar I was able to move past my previous error message. Right now, however I am receiving a different error message posted below:
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
FINAL EDIT
Altering the subquery like so allowed me to return multiple deleted records into the Audit table as I was only requesting one record at a time.
IF @action = 'D'
BEGIN
INSERT INTO TransactionLog (TransactionDate, Operator, TableName, Action, TableString, UserId)
SELECT LastChangeDate, 'Op', 'Agent', 'D',
CAST('SymNum:' + CAST(SymetraNumber as nvarchar(30)) + ' entType:' + EntityType + ' Fname:' + ISNULL(FirstName, 'NULL') + ' Lname:' + ISNULL(LastName, 'NULL') +
' suff:' + ISNULL(NameSuffix, 'NULL') + ' corpName:' + ISNULL(CorporateName, 'NULL' ) + ' ctrlId:' + ISNULL(CAST(ControlId as nvarchar(30)), 'NULL') AS nvarchar(30)) as TableString
, LastChangeOperator
FROM deleted
END
ELSE
That
select @sNumber = sNumber, ..syntax will overwrite the variables once for each row, so you end up only with the last row’s values.And then you also do an
insert into ... values (...), which can only insert one row.You should try to rewrite it in the form:
You can use
ISNULL(lastname, 'NULL')instead of your if-statements.