Dynamically finding column values in a trigger from INSERT when the column name is a variable
-
06-09-2019 - |
Question
I have a trigger that gets inserts and updates to a view. I need to find the columns that are being modified and get the value into the correct table.
INSERT INTO TempTableAttr_Lot(ID, [% Num]) VALUES(3, 24.0)
I am trying to figure out how, in my trigger, to get the value of ID and [% Num] columns. The problem is that there can be 32 different columns that are set in the insert or update, so I want to loop through looking to see if that column is in the 'inserted' table.
One problem is that if I use exec or execute, to build a dynamic query, inserted is not in scope for this.
The view is dynamic in that if attributes are added then the view is regenerated by a stored procedure, so I can't assume what column names are in the view at any given time, it can grow and shrink.
Ideally I would like to do SET @Value = (SELECT i.[@Name] FROM inserted i)
But @Name is not a column name, but a variable in my trigger, so when I tried
DECLARE @ValueTable TABLE ( value sql_variant)
INSERT INTO @ValueTable EXECUTE('SELECT i.[' + @Name + '] FROM inserted i')
SET @Value = CONVERT(nvarchar(128), (SELECT DISTINCT * FROM @ValueTable))
this didn't work as inserted appears to not be in scope.
For the first loop @Name = 'ID' and for the second it will be 'Col2' which was not inserted, so the value of @Value should be null, and I continue to loop through the possible column names until I finish, and the trigger is processed.
I am calling it a trigger, it is defined as:
CREATE TRIGGER TempTableAttr_LotTrigger
ON TempTableAttr_Lot
INSTEAD OF UPDATE, INSERT
I am testing with an INSERT command at the moment. I realize that when doing an update I may need to look at the 'deleted' table.
UPDATE: I am assuming only one row is being inserted at the moment, for my test, to see how to get this to work. This is for an entity-attribute-value database, but I have a view that makes it look relational. When using Integration Service, when the updating is going on, any inserts or updates to the view will call the trigger. I am just trying to understand how to get the information I need so I can update the correct table, with the correct values.
Solution
To get access to the INSERTED table you can do the following.
SELECT * INTO #MYINSERTED FROM INSERTED
EXEC('SELECT * FROM #MYINSERTED')
DROP TABLE #MYINSERTED
OTHER TIPS
CREATE TRIGGER triggerRowLog_tblMember
--After INSERT
ON dbo.tblMember
AFTER UPDATE
--for EACH ROW
As
BEGIN
DECLARE @temptblCategory TABLE (
idx smallint Primary Key IDENTITY(1,1)
, CategoryID int
, CategoryName nvarchar(100)
)
declare @i int
set @i = 1
declare @catcount int
set @catcount = 0
Select @catcount= Count(*) from tblCategoryMst Where Tag = 'A' or Tag = 'L' and Active =1
declare @CatName nvarchar(100)
declare @CatID int
declare @ValueCompare nvarchar(100)
declare @PrevValueCompare nvarchar(100)
if(@catcount > 0)
begin
INSERT @temptblCategory
SELECT distinct CategoryID, CategoryName FROM tblCategoryMst Where (Tag = 'A' or Tag = 'L' )and (TableName = 'Transactions' or TableName ='tblMember') and Active =1
While @i <= @catcount
Begin
set @CatName = (SELECT CategoryName FROM @temptblCategory WHERE idx = @i)
set @CatID = (SELECT CategoryID FROM @temptblCategory WHERE idx = @i)
if(@CatName = 'Form')
Begin
set @CatName = @CatName + 'Member'
End
else if(@CatName = 'Type')
Begin
set @CatName = 'Membership' + @CatName
End
else if(@CatName = 'Address')
Begin
set @CatName = 'Cor' + @CatName
End
declare @Query nvarchar(4000)
SELECT * INTO #MYInserted FROM Inserted
SELECT * INTO #MYDeleted FROM Deleted
set @Query ='(Select @PrevValueCompare = ' + @CatName+' from #MYDeleted )'
exec sp_executesql @Query ,N'@PrevValueCompare nvarchar(50) output', @PrevValueCompare output
set @Query ='(Select @ValueCompare = ' + @CatName+' from #MYInserted )'
exec sp_executesql @Query ,N'@ValueCompare nvarchar(50) output', @ValueCompare output
DROP TABLE #MYInserted
DROP TABLE #MYDeleted
if( @ValueCompare <> 'no compare' and @ValueCompare <> @PrevValueCompare)
Begin
INSERT INTO dbo.tblLogMst(ID,IDOf,CategoryID, PreviousData, ChangedData,
ExchangeCode,CreatedBy,CreatedIP )
SELECT i.MemberID,'MS',@CatID, @PrevValueCompare, @ValueCompare ,
i.ExchangeCode,i.UpdatedBy,i.UpdatedIP
FROM Inserted i
INNER JOIN Deleted d ON i.MemberID = d.MemberID
End
set @i = Convert(int,@i) + Convert(int,1)
End
end
END;