MSSQL Trigger - Updating newly inserted record on INSERT - sql-server

I wish to make a modification (Set Deleted = 1) to rows being inserted into my table CustomerContact if the SELECT statement returns more than 0.
I have the following, but it remains untested:
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
DECLARE #numrows INT;
/* Determine if order matches criteria for marking customer contact as DELETED immediately */
SELECT #numrows = COUNT(*)
FROM [Order] o
JOIN OrderMeterDetail om
ON o.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
AND o.orderid IN (SELECT OrderID FROM INSERTED);
/* If the order matches the criteria, mark the customer contact as deleted */
IF (#numrows >= 1)
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM INSERTED);
END
Within my IF statement, I am using FROM INSERTED, assuming that this will return the newly inserted id for the record that was created by the insert.
I have two questions about this statement:
Will this part of the statement perform an UPDATE just the record
that was just inserted into CustomerContact?
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM INSERTED);
Is this the way that would be deemed correct to make a change to a row that has just been inserted based on the result of a SELECT statement?
CustomerContactID is an auto-incrementing primary key column.

You say "Just the record that was inserted". Inserted can contain more than one record. If there is only one, then your trigger will function as you expect. But if there is more than one, it won't.
I would rewrite your logic into a single update statement along the lines of...
Update CustomerContact
Set Deleted = 1
From CustomerContact
inner join inserted on CustomerContact.CustomerContactID = inserted.CustomerContactID
inner join orders on inserted.OrderID = orders.OrderID
where
-- some criteria.

CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
DECLARE #numrows INT;
/* Determine if order matches criteria for marking customer contact as DELETED immediately */
-- Get all the records into a temp table
SELECT * INTO #Temp
FROM inserted
Declare #ID int;
SELECT #numrows = COUNT(*)
FROM [Order] o
JOIN OrderMeterDetail om
ON o.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
AND o.orderid IN (SELECT OrderID FROM #Temp);
IF (#numrows >= 1)
BEGIN
WHILE EXISTS (SELECT TOP 1 * FROM #Temp)
BEGIN
SELECT TOP 1 #ID = ID FROM #Temp
/* If the order matches the criteria, mark the customer contact as deleted */
UPDATE CustomerContact
SET Deleted = 1
WHERE CustomerContactID IN (SELECT CustomerContactID FROM #Temp WHERE ID = #ID);
DELETE FROM #Temp WHERE ID = #ID
END
END
DROP TABLE #Temp
END
I think you can do something like this, tweak the code to futher suit for needs, hope this will help.

Here is the final solution that I used to solve this issue:
CREATE TRIGGER mark_cust_contact_deleted ON CustomerContact
AFTER INSERT AS
BEGIN
UPDATE CustomerContact
SET Deleted = 1
FROM CustomerContact cc
JOIN inserted i
ON cc.CustomerContactID = i.CustomerContactID
JOIN [Order] o
ON i.OrderID = o.OrderID
JOIN OrderMeterDetail om
ON i.OrderID = om.OrderID
WHERE o.WorkTypeID = 3 AND o.WorkActionID = 26 AND o.WorkStageID IN (109, 309, 409)
AND om.MeterDetailTypeID = 1 AND om.MeterLocationID IN (2, 4)
END

Related

Ms Sql Insert Trigger To Affect Other Table

I am trying to put table b value when table a inserted but nothing effects on table b. Its like there is no trigger. Do you have any suggestion. I have tried below but no result.
alter trigger triggername on tablea after insert as
begin
update tablea set valuetablea_a = valuetablea_b where id = (select distince id from inserted)
end
begin
update tableb set valuetableb_a = (select valuetablea_a from tablea where id = (select distincd id from Inserted))
where date = (select distinct date from Inserted)
end
Try this:
ALTER TRIGGER triggername ON tablea AFTER INSERT AS
BEGIN
UPDATE a
SET
valuetablea_a = I.valuetablea_b
FROM tablea A
INNER JOIN inserted I
ON A.Id = I.Id
UPDATE B
SET
valuetableb_a = A.valuetablea_a
FROM tableb B
INNER JOIN tablea
ON 1=1 AND EXISTS
(
SELECT 1 FROM inserted WHERE ID = A.ID AND [Date] = B.DATE
)
end
In the first update, you are giving this
update tablea set valuetablea_a = valuetablea_b
Which means From TableA update the value from column valuetablea_b to valuetablea_a for each row that was updated. Instead of getting the values from the Updated valuetablea_b column
2nd Update updates the values in TableB.valuetableb_a by matching the Id and Date fileds in the updated records

Cursor on a trigger

I'm using SQL Server 2008.
I have an after trigger for INSERT, UPDATE and DELETE action defined in the table. My problem is that currently my trigger inserts one record at a time and I need multiple records as for one
SELECT TOP 1 #ParentID FROM ... WHERE ID = #ID
returns multiple unique records.
(See this comment below "-- this subquery returns more than 1 value, so I need to insert in the search Audit table as many ParentIDs as it returns")
I believe I need to use cursor, but I'm not sure where exactly to declare and open cursor.
--CREATE PROCEDURE [dbo].[SP_Auditing]
-- #ID INT, #Code VARCHAR(3), #AuditType VARCHAR(10), #ParentCode VARCHAR(3) = NULL, #ParentID INT = NULL
--AS
--BEGIN
-- INSERT INTO myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
-- VALUES(#ID, #Code, #AuditType, #ParentCode, #ParentID)
--END
GO
CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL] ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE NOT FOR REPLICATION
AS
BEGIN
DECLARE #ID INT, #Code VARCHAR(3), #AuditType VARCHAR(10), #ParentCode VARCHAR(3), #ParentID INT SET #Code = 'DOC'
IF EXISTS (SELECT 1 FROM inserted) AND
NOT EXISTS (SELECT 1 FROM deleted)
BEGIN
SELECT TOP 1
#ID = ins.ID,
#ParentID = (
SELECT TOP 1 CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT)
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)
ON t.Id = v.ID
WHERE v.ID = #ID --284
), **-- this subquery returns more than 1 value, so I need to insert in the search Audit table as many ParentIDs as it returns**
#AuditType = 'INSERT' FROM inserted ins
IF #ID IS NOT NULL
AND
#ParentID IS NOT NULL
AND
#ParentCode IS NOT NULL
EXEC [MyDB].[dbo].SP_Auditing] #ID, #Code, #AuditType, #ParentCode, #ParentID
END
-- below is the same logic for UPDATE and DELETE actions...
The stored procedure above simply inserts data into the Audit table.
Never use scalar variables in triggers because insert, update, and delete may affect multiple rows. As to your trigger, try something like this.
CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL]
ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE
NOT FOR REPLICATION
AS
BEGIN
;with act as (
select isnull(i.id,d.id) id, --either deleted or inserted is not null
case when i.id is not null and d.id is not null then 'update'
when i.id is not null then 'insert'
else 'delete' end auditType
from inserted i full outer join deleted d on i.id = d.id
),
audit_cte as (
SELECT act.id, 'DOC' Code,
CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT) parentid,
act.auditType, 'parentcode' parentCode
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK) ON t.Id = v.ID
inner join act on act.id = t.id
)
insert myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
select id,code,AuditType, ParentCode, ParentID
from audit_cte
where parentCode is not null and parentid is not null
end
Why do you need to get the records one by one? From my understanding you want to keep the log.
IF EXISTS (SELECT 1 FROM inserted) AND
NOT EXISTS (SELECT 1 FROM deleted)
BEGIN
INSERT INTO [Your_Log_Table]
SELECT
ins.ID, [Code],'INSERT',[PrentCode],
(SELECT TOP 1 CAST(RIGHT(parentId,LEN(parentId) -
LEN(LEFT(parentId,3))) AS INT)
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK)
ON t.Id = v.ID
WHERE v.ID = ins.ID --284
)
FROM inserted ins
END
See Alex Kudryashev's answer. I needed to tweak a little his logic to sort out duplicate records with the same ParentIDs for the insertion into the Audit table. I added one more cte just below Alex's cte_Audit as follows
CREATE TRIGGER [dbo].[Tr_MyFavouriteTable_UPD_INSERT_DEL]
ON [dbo].[MyFavouriteTable] AFTER INSERT, DELETE, UPDATE
NOT FOR REPLICATION
AS
BEGIN
;with act as (
select isnull(i.id,d.id) id, --either deleted or inserted is not null
case when i.id is not null and d.id is not null then 'update'
when i.id is not null then 'insert'
else 'delete' end auditType
from inserted i full outer join deleted d on i.id = d.id
),
audit_cte as (
SELECT act.id, 'DOC' Code,
CAST(RIGHT(parentId,LEN(parentId) - LEN(LEFT(parentId,3))) AS INT) parentid,
act.auditType, 'parentcode' parentCode
FROM [MyDB].[dbo].[MyFavouriteTable] t WITH (NOLOCK)
INNER JOIN [MyDB2].[dbo].[MyView] v WITH (NOLOCK) ON t.Id = v.ID
inner join act on act.id = t.id
)
insert myDB.dbo.Table1 (ID, Code, AuditType, ParentCode, ParentID)
select id,code,AuditType, ParentCode, ParentID
from audit_cte
where parentCode is not null and parentid is not null
,CTE_dupsCleanup AS (
SELECT DISTINCT
Code,
Id,
AuditType,
ParentCode,
ParentId,
-- ROW_NUMBER() OVER(PARTITION BY ParentId, ParentCode, AuditType ORDER BY ParentId) AS Rn
FROM AUDIT_CTE
WHERE ParentCode IS NOT NULL
AND ParentId IS NOT NULL )
Then using Rn = 1 inserted only unique records into the Auidt table. Like this:
INSERT [ISSearch].[dbo].[SearchAudit] (Code, ID, AuditType, ParentCode, ParentID)
SELECT
Code,
ID,
AuditType,
ParentCode,
ParentId
FROM CTE_dupsCleanup
-- WHERE Rn = 1
END

Creating a single trigger for Insert/Update

I am using SQL Server 2008.
Assuming I have Table A which is a transaction table. And Table B which is a history table.
Whenever a row is inserted or updated in Table A, a new row should be inserted in Table B.
The Status column of Table B should change to INSERTED or UPDATED respectively.
How to handle this from a single trigger?
What you're asking for is quite simple:
CREATE TRIGGER TR_TableA_IU ON dbo.TableA FOR INSERT, UPDATE
AS
SET NOCOUNT ON;
INSERT dbo.TableB (Column1, Column2, Status)
SELECT
I.Column1,
I.Column2,
CASE WHEN EXISTS (SELECT * FROM Deleted) THEN 'UPDATED' ELSE 'INSERTED' END
FROM Inserted I;
If you also wanted to handle deletions, that can be done in a single statement, too:
CREATE TRIGGER TR_TableA_IUD ON dbo.TableA FOR INSERT, UPDATE, DELETE
AS
SET NOCOUNT ON;
INSERT dbo.TableB (Column1, Column2, Status)
SELECT
I.Column1,
I.Column2,
CASE WHEN EXISTS (SELECT * FROM Deleted) THEN 'UPDATED' ELSE 'INSERTED' END
FROM
Inserted I
UNION ALL
SELECT
D.Column1,
D.Column2,
'DELETED'
FROM Deleted D
WHERE NOT EXISTS (
SELECT * FROM Inserted
);
Wow, there are a lot of outright-wrong and semi-wrong (at least in being overcomplicated) answers given so far.
Assuming that both tables:
has an "Id" column as primary key.
has the same schema, except that history table has an extra "Status" column at the end.
You can create a trigger like this:
CREATE TRIGGER dbo.TableA_InsUpd
ON dbo.TableA
AFTER INSERT, UPDATE, DELETE
AS
BEGIN
Insert Into TableB
Select i.*, 'INSERTED'
From inserted i
Where not exists ( Select * From deleted d Where d.Id = i.Id )
Update B
Set [Status] = 'UPDATED',
Field1 = i.Field1,
Field2 = i.Field2
From TableB B
Inner Join inserted i On i.Id = B.Id
Where exists ( Select * From deleted d Where d.Id = i.Id )
Update B
Set [Status] = 'DELETED'
From TableB B
Inner Join deleted d On d.Id = B.Id
Where not exists ( Select * From inserted i Where i.Id = d.Id )
END
Here is a SqlFiddle with the complete code
(Note this will fail if a record Id is deleted and then inserted again)
Try this code
CREATE TRIGGER YouTriggerName
ON TableA
AFTER INSERT,DELETE,UPDATE
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Insert statements for trigger here
DECLARE #type NVarChar(15)=
CASE when not exists(SELECT * FROM inserted)
THEN 'Deleted'
WHEN exists(SELECT * FROM deleted)
THEN 'Updated'
ELSE
'Inserted'
END
/*
TableB should contains all the columns of TableA
OR tweak it to suit your need
*/
IF #type = 'Deleted' BEGIN
INSERT INTO TableB
SELECT *, #type Stat FROM deleted
END
ELSE BEGIN
INSERT INTO TableB
SELECT *, #type Stat FROM inserted
END
END
NOTE
You will get this error if TableB has identity on since we use (select *)
An explicit value for the identity column in table 'TableB' can only be specified when a column list is used and IDENTITY_INSERT is ON.
this is tested.here employee and employee have same table structure.0 means updated and 1=inserted,2=deleted
Alter trigger trgTest on dbo.employee
AFTER INSERT, UPDATE,Delete
as
Begin
Set noCount on
if exists(select e.id from deleted e inner join inserted i on e.ID=i.id )
Begin
insert into Employee1
select id,name,0 from inserted
End
else if exists(select e.id from Employee1 e inner join deleted d on e.ID=d.id)
Begin
insert into Employee1
select id,name,2 from deleted
End
else
Begin
insert into Employee1
select id,name,1 from inserted
End
End

SQL Server UPDATE with WHERE spanning over 2 tables

I have a SQL Server database and I need to manually do an update query. There for no solutions using any programming language can be used.(stored procedures can be used)
I have 4 tables affected (/used) in the query.
[Orders]
[StatusHistoryForOrder]
[StatusHistory]
[Statuses]
I need to update the field [Orders].[OrderStatusID] which is a foreign key to [Statuses]. (So actually changing the state of the order. The table [StatusHistoryForOrder] is a linking table to [StatusHistory] and only contains 2 colums.
[StatusHistoryForOrder].[OrderId]
[StatusHistoryForOrder].[OrderStatusHistoryid]
Don't say that this is not logically cause I already know that. The company who designed the database is a complete retarded company but the database is now too large to set things straight and there is neither the time or money to do it.
The [StatusHistory] table has multiple columns:
[StatusHistory].[OrderStatusHistoryId]
[StatusHistory].[OrderStatusId]
[StatusHistory].[Date]
[StatusHistory].[Message]
The [StatusHistory].[OrderStatusId] is also a foreign key to [Statuses].
In the update query I need to update the status of the order to status 16. But only on rows that now have status 1 and are older then 60 days. I know I can check the date by using the function
DATEDIFF(DD,[StatusHistory].[Date],GETDATE()) > 60
But how to implement this query if the date field is not in the orders. And to set the new [StatusHistory] a new row has to be made for that table and the [StatusHistoryForOrder] table also needs a new row and the ID of that row needs to be set in the [Orders] table row.
Does anyone know how to do this? I am fairly new to SQL Server (or SQL for that matter) and I have absolutly no clue where to begin.
Conclusion:
I need a stored procedure that first checks every row in [Orders] if the [StatusHistory].[Date] (which is linked to the order using foreign keys) of that order is older that 60. If it is older then a new StatusHistory row must be inserted with the current date and status 16. Then in [StatusHistoryForOrder] a new row must be inserted with the new ID of the statusHistory been set in [StatusHistoryForOrder].[OrderStatusHistoryid] and the order id set in [StatusHistoryForOrder].[OrderId]. And last but not least: The [Orders].[OrderStatusID] also needs to be set to 16.
A select query to select the date and status of the order:
SELECT TOP (100) PERCENT
dbo.Orders.OrderID,
dbo.Statuses.Description AS Status,
dbo.StatusHistory.Date
FROM
dbo.Orders
INNER JOIN
dbo.Statuses
ON
dbo.Orders.OrderStatusID = dbo.Statuses.StatusId
INNER JOIN
dbo.StatusHistoryForOrder
ON
dbo.Orders.OrderID = dbo.StatusHistoryForOrder.OrderId
INNER JOIN
dbo.StatusHistory
ON
dbo.StatusHistoryForOrder.OrderStatusHistoryid = dbo.StatusHistory.OrderStatusHistoryId
WHERE
(dbo.Statuses.StatusId = 1)
AND
(DATEDIFF(DD, dbo.StatusHistory.Date, GETDATE()) > 60)
UPDATE
For #marc_s:
Can anyone help me with that?
Try this CTE (Common Table Expression) to find all those orders - does it work, are the results plausible? (this doesn't update anything just yet - just SELECTing for now):
USE (your database name here)
GO
DECLARE #OrdersToUpdate TABLE (OrderID INT, StatusHistoryID INT, StatusDate DATETIME)
;WITH RelevantOrders AS
(
SELECT
o.OrderId, sh.Date
FROM dbo.Orders o
INNER JOIN dbo.StatusHistoryForOrder ho ON ho.OrderId = o.OrderId
INNER JOIN dbo.StatusHistory sh ON ho.OrderStatusHistoryid = sh.OrderStatusHistoryid
WHERE
sh.Date <= DATEADD(D, -60, GETDATE()) -- older than 60 days back from today
AND o.OrderStatusID = 1 -- status = 1
)
INSERT INTO #OrdersToUpdate(OrderID, StatusDate)
SELECT OrderID, [Date]
FROM RelevantOrders
BEGIN TRANSACTION
BEGIN TRY
DECLARE #OrderIDToInsert INT, -- OrderID to process
#InsertedStatusHistoryID INT -- new ID of the inserted row in StatusHistory
-- grab the first OrderID that needs to be processed
SELECT TOP 1 #OrderIDToInsert = OrderID
FROM #OrdersToUpdate
WHERE StatusHistoryID IS NULL
ORDER BY OrderID
-- as long as there are still more OrderID to be processed ....
WHILE #OrderIDToInsert IS NOT NULL
BEGIN
PRINT 'Now inserting new StatusHistory entry for OrderID = ' + CAST(#OrderIDToInsert AS VARCHAR(10))
INSERT INTO dbo.StatusHistory(OrderStatusID, [Date], [Message])
VALUES(16, GETDATE(), 'Bulk Insert/Update operation') -- enter here whatever you want to store
SELECT #InsertedStatusHistoryID = SCOPE_IDENTITY(); -- grab newly inserted ID
PRINT 'New StatusHistory entry inserted with ID = ' + CAST(#InsertedStatusHistoryID AS VARCHAR(10))
UPDATE #OrdersToUpdate
SET StatusHistoryID = #InsertedStatusHistoryID
WHERE OrderID = #OrderIDToInsert
-- safety - reset #OrderIDToInsert to NULL so that we'll know when we're done
SET #OrderIDToInsert = NULL
-- read next OrderID to be processed
SELECT TOP 1 #OrderIDToInsert = OrderID
FROM #OrdersToUpdate
WHERE StatusHistoryID IS NULL
ORDER BY OrderID
END
-- insert into the StatusHistoryForOrder table
INSERT INTO dbo.StatusHistoryForOrder(OrderID, OrderStatusHistoryID)
SELECT OrderID, StatusHistoryID
FROM #OrdersToUpdate
-- update your Orders to status ID = 16
UPDATE dbo.Orders
SET OrderStatusID = 16
FROM #OrdersToUpdate upd
WHERE dbo.Orders.OrderID = upd.OrderID
COMMIT TRANSACTION
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
ROLLBACK TRANSACTION
END CATCH
This CTE basically joins your Orders table to the StatusHistory table (via the intermediate link table) and selects the values you're interested in (hopefully!).
This particular problem seems solvable with set operations only.
DECLARE #Orders TABLE (ID int, rownum int IDENTITY);
DECLARE #StatusHistory TABLE (ID int, rownum int IDENTITY);
/* get the list of orders with expired statuses */
INSERT INTO #Orders (ID)
SELECT o.OrderID
FROM Orders o
INNER JOIN StatusHistoryForOrder shfo ON o.OrderID = shfo.OrderId
INNER JOIN StatusHistory sh ON shfo.OrderStatusHistoryid = sh.OrderStatusHistoryId
GROUP BY o.OrderID
HAVING DATEDIFF(DD, MAX(sh.Date), GETDATE()) > 60
/* add so many new rows to StatusHistory and remember the new IDs */
INSERT INTO StatusHistory (OrderStatusId, Date, Message)
OUTPUT inserted.OrderStatusHistoryId INTO #StatusHistory (ID)
SELECT
16,
GETDATE(),
'Auto-inserted as the previous status has expired'
FROM #Orders
/* join the two temp lists together and add rows to StatusHistoryForOrder */
INSERT INTO StatusHistoryForOrder (OrderId, OrderStatusHistoryid)
SELECT o.ID, sh.ID
FROM #Orders o
INNER JOIN #StatusHistory sh ON o.rownum = sh.rownum
/* finally update the statuses in Orders */
UPDATE Orders
SET OrderStatusID = 16
FROM #Orders o
WHERE Orders.OrderID = o.ID
This should be the body of a single transaction, of course.

Checking if something has changed in a trigger

I have a need to monitor a subset of fields on a table and perform a task when one of them changes.
I am using a trigger on the table update which and then am looking at the changes as follows:
-- join the deleted and inserted to get a full list of rows
select * into #tmp from (select * from inserted union select * from deleted) un
-- select a count of differing rows, > 1 means something is different
select distinct count(*) from #tmp
This is fine and a count of 2 or more means something is different on single line updates. Issue is if I am doing a multiple line update then this breaks down.
Is there a way I can get this to work for a multi line update or do I need to try a different approach completely.
You could do something like this (syntax completely untested)
IF NOT UPDATE(col)
RETURN
SELECT inserted.key, inserted.col as i_col, deleted.col as d_col
INTO #interestingrows
FROM inserted JOIN deleted on inserted.key = deleted.key
and inserted.col <> deleted.col /*If col is nullable cater for that as well*/
IF ##ROWCOUNT=0
RETURN
/*Process contents of #interestingrows*/
I ended up with a fairly simple solution. I wrote an additional loop around the check that did the check per line in inserted.
-- get a list of updated line id's
select field1 as id into #loop from inserted
-- loop through all the id's and do a compare
while (select count(*) from #loop) > 0 begin
select top 1 #id = id from #loop
select * into #tmp from (select * from inserted where field1 = #id union
select * from deleted where field1 = #id) un
-- do a select ditinct to count the differing lines.
if (select distinct count(*) from #tmp) > 1 begin
-- the 2 lines don't match, so mark for update
update test1 set flag = 1 where field1 = #id
end
drop table #tmp
delete #loop where id = #id
end

Resources