Click here to monitor SSC
SQLServerCentral is supported by Red Gate Software Ltd.
 
Log in  ::  Register  ::  Not logged in
 
 
 
        
Home       Members    Calendar    Who's On


Add to briefcase 123»»»

Weird Behavior of Trigger Expand / Collapse
Author
Message
Posted Wednesday, February 13, 2013 1:04 PM
Valued Member

Valued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued Member

Group: General Forum Members
Last Login: Thursday, April 11, 2013 7:58 AM
Points: 55, Visits: 71
I've got a trigger (SQL 2008 R2) that does a few simple operations but the results are not logical.

A text file is fed to an SSIS package that loads the records into "RLFL" table. The Data Access Mode is set to "Table or view"

Here is the trigger for RLFL:
ALTER TRIGGER [dbo].[ArchiveBACK] ON [dbo].[RLFL]
AFTER INSERT
AS
BEGIN
SET NOCOUNT ON;

DECLARE @soNo varchar(10),@releaseDate smalldatetime

SELECT @soNo = soNo FROM INSERTED
SELECT @releaseDate=releaseDate FROM INSERTED


-- Check if BACK records were archived, if NOT...
IF(SELECT COUNT(1) FROM BACK_RLFL WHERE salesOrderNo=@soNo AND releaseDate=@releaseDate AND releaseVersion='1') = 0
-- Archive BACK Records, with version 1
INSERT INTO BACK_RLFL SELECT *, @releaseDate,'1' FROM BACK WHERE salesOrderNo=@soNo

END

Now, the BACK table has at least 3 to 4 rows for that soNo (key) that was just inserted into RLFL, however the result in BACK_RLFL after the trigger executes has only the last row from BACK.

If I manually insert a record into RLFL, I get the desired results where all four rows from BACK transfer into RLFL_BACK (exactly what the trigger is supposed to do).

Can anyone explain what's happening?

Thanks,
Mark
Post #1419720
Posted Wednesday, February 13, 2013 1:21 PM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Yesterday @ 3:18 PM
Points: 37,744, Visits: 30,025
That trigger assumes that any insert operation inserts one and only one row. An insert that inserts more than one row will result in weird behaviour. I would imagine that's what you're seeing.

To fix it, you need to change the trigger so that it doesn't assume there's only a single row in the inserted table.



Gail Shaw
Microsoft Certified Master: SQL Server 2008, MVP
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

We walk in the dark places no others will enter
We stand on the bridge and no one may pass

Post #1419725
Posted Wednesday, February 13, 2013 1:51 PM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Tuesday, May 21, 2013 1:02 PM
Points: 477, Visits: 3,652
I was playing around with this, and came up with this as a pretty simple approach:

ALTER TRIGGER [dbo].[ArchiveBACK] ON [dbo].[RLFL]
AFTER INSERT
AS
SET NOCOUNT ON;

INSERT INTO BACK_RLFL
SELECT * FROM INSERTED
EXCEPT
SELECT * FROM BACK_RLFL

;


______________________________________________________________________________
How I want a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.
Post #1419738
Posted Thursday, February 14, 2013 10:14 AM
Valued Member

Valued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued Member

Group: General Forum Members
Last Login: Thursday, April 11, 2013 7:58 AM
Points: 55, Visits: 71
That does not work.

Here are my table layouts:

BACK Table:
OrderID ItemNo
--------- ---------
9813 1
9813 2
9813 3
9817 1

RLFL gets one record inserted which is OrderID 9813

Trigger is supposed to fire:
INSERT INTO BACK_ARCHIVE SELECT * FROM BACK WHERE OrderID=INSERTED.OrderID

Pretty simple so far...

The results I get in my BACK_ARCHIVE (identical layout to BACK) Table are
OrderId       ItemNo
--------- ----------
9813 3

Note, it's always the LAST item that gets recorded int BACK_ARCHIVE.

WHY? I need all of them in BACK_ARCHIVE.

I believe it has something to do with the way SSIS processes it using "OLE DB Destination" because if I insert a record into RLFL manually, the trigger does exactly what it's supposed to do and inserts all 3 records from BACK.

I'm thinking of an sp, but i'd rather not add another level of complexity for something so trivial, supposedly.

How can I accomplish this?

Thanks.
Post #1420181
Posted Thursday, February 14, 2013 10:18 AM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Yesterday @ 3:18 PM
Points: 37,744, Visits: 30,025
Mark-545947 (2/14/2013)
Note, it's always the LAST item that gets recorded int BACK_ARCHIVE.

WHY? I need all of them in BACK_ARCHIVE.


As I said earlier

That trigger assumes that any insert operation inserts one and only one row (the selecting of a row into a variable). An insert that inserts more than one row will result in weird behaviour (because it will only process one of the rows in the inserted table).

I believe it has something to do with the way SSIS processes it using "OLE DB Destination" because if I insert a record into RLFL manually, the trigger does exactly what it's supposed to do and inserts all 3 records from BACK.


If you insert a single row it will work as expected. If you insert multiple rows it will not work as expected.

How can I accomplish this?



To fix it, you need to change the trigger so that it doesn't assume there's only a single row in the inserted table.



Gail Shaw
Microsoft Certified Master: SQL Server 2008, MVP
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

We walk in the dark places no others will enter
We stand on the bridge and no one may pass

Post #1420184
Posted Thursday, February 14, 2013 10:45 AM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Tuesday, May 21, 2013 1:02 PM
Points: 477, Visits: 3,652
Mark-545947 (2/14/2013)
That does not work.


Sure it does for the situation of archiving what is not already there, but now you've introduced a new table, BACK_ARCHIVE. So I see four tables: BACK, RLFL, RLFL_BACK, and BACK_ARCHIVE. Can you describe what the process is between these tables? Which one is first and what is the trigger supposed to do after that?


______________________________________________________________________________
How I want a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.
Post #1420205
Posted Thursday, February 14, 2013 10:50 AM
Valued Member

Valued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued Member

Group: General Forum Members
Last Login: Thursday, April 11, 2013 7:58 AM
Points: 55, Visits: 71
I don't understand.

I only have one row that I'm processing in SSIS. Just like I'd be processing one row with an INSERT statement from SSMS (which works flawlessly).

How do I tell the trigger that there are more than one record being inserted?


Thanks
Post #1420209
Posted Thursday, February 14, 2013 10:52 AM
Valued Member

Valued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued MemberValued Member

Group: General Forum Members
Last Login: Thursday, April 11, 2013 7:58 AM
Points: 55, Visits: 71
Sure it does for the situation of archiving what is not already there, but now you've introduced a new table, BACK_ARCHIVE. So I see four tables: BACK, RLFL, RLFL_BACK, and BACK_ARCHIVE. Can you describe what the process is between these tables? Which one is first and what is the trigger supposed to do after that?


No, to make it easier I just renamed the tables.

Target table is RLFL.
LIVE table BACK
Archive is BACK_RLFL

I'm just so confused with this issue. There are only 3 tables involved. Sorry for the confusion.

I simplified the process and described it in the 4th post.
Post #1420210
Posted Thursday, February 14, 2013 12:13 PM


SSC-Dedicated

SSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-DedicatedSSC-Dedicated

Group: General Forum Members
Last Login: Yesterday @ 3:18 PM
Points: 37,744, Visits: 30,025
Mark-545947 (2/14/2013)
How do I tell the trigger that there are more than one record being inserted?


There's no 'telling the trigger' anything. As far as SQL is concerned, a trigger works on sets of rows, it's not something that's called per-row.

This portion of your trigger will only behave correctly if there's only one row in the inserted table

DECLARE @soNo varchar(10),@releaseDate smalldatetime

SELECT @soNo = soNo FROM INSERTED
SELECT @releaseDate=releaseDate FROM INSERTED

If there's more than one row in Inserted (as there will automatically be if the insert affects more than one row), those selects will fetch one row's data. Which one is not defined, but it will only be one.

You must write your trigger so that it can handle multiple rows in the inserted table, not assume there's one row and assign it to variables.



Gail Shaw
Microsoft Certified Master: SQL Server 2008, MVP
SQL In The Wild: Discussions on DB performance with occasional diversions into recoverability

We walk in the dark places no others will enter
We stand on the bridge and no one may pass

Post #1420238
Posted Thursday, February 14, 2013 12:22 PM
SSC-Addicted

SSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-AddictedSSC-Addicted

Group: General Forum Members
Last Login: Tuesday, May 21, 2013 1:02 PM
Points: 477, Visits: 3,652
Mark-545947 (2/14/2013)
Sure it does for the situation of archiving what is not already there, but now you've introduced a new table, BACK_ARCHIVE. So I see four tables: BACK, RLFL, RLFL_BACK, and BACK_ARCHIVE. Can you describe what the process is between these tables? Which one is first and what is the trigger supposed to do after that?


No, to make it easier I just renamed the tables.

Target table is RLFL.
LIVE table BACK
Archive is BACK_RLFL

I'm just so confused with this issue. There are only 3 tables involved. Sorry for the confusion.

I simplified the process and described it in the 4th post.


I've attempted to take your logic from the trigger and make into a trigger that doesn't rely on variables. It looks like an insert to RLFL will only be written to BACK_RLFL if there is already a matching OrderID in BACK.

See if this makes sense to you.


create table RLFL (OrderID int, ItemNo int);
GO
create table BACK (OrderID int, ItemNo int);
GO
create table BACK_RLFL (OrderID int, ItemNo int);
GO
CREATE TRIGGER [dbo].[ArchiveBACK] ON [dbo].[RLFL]
AFTER INSERT
AS
SET NOCOUNT ON;

INSERT INTO BACK_RLFL
SELECT b.*
FROM BACK b
INNER JOIN INSERTED i on b.OrderID = i.OrderID
GO



______________________________________________________________________________
How I want a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.
Post #1420242
« Prev Topic | Next Topic »

Add to briefcase 123»»»

Permissions Expand / Collapse