Have trigger, attached to table getting multiple inserts, update 1 row at a time

  • Hi there, I'm doing a multiple insert thru a sproc on a table StudentLog (meaning there are several rows inserted at once).

    StudentID StudentGrade StudentRemarks

    ---1-------------8

    ---2-------------9

    ---3-------------7

    Now I'd like to update the column StudentRemarks with values from table ClassRemarks so I attached a For Insert trigger to StudentLog which selects StudentRemarks by StudentID, from ClassRemarks, and updates the StudentRemarks column for that student. At least that's the way I expected it to behave, i.e. row 1 gets inserted, the trigger fires, gets StudentRemark for Student 1, updates the StudentRemarks column, then moves to the next row, does the same with student 2, and so on. But what really happens is that all the StudentRemarks on row 2 and 3 get the same value of StudentsRemark from Student 1. so it seems that since this is a multiple insert (3 rows at once in this case) the trigger only fires at the beginning of the insert.

    Does this work this way really? Is there an easy solution to it, other than writing an iterating procedure on the client side. I'd rather not since this is an asp.net app, which means I like to avoid unnecessary roundtrips to the db whenever I can (and the real data involves much more columns).

    Appreciate any lights shed,

    Jaime

  • Hello,

    You are correct in thinking that the Trigger will only fire one time when inserting multiple records at once.

    There is an “Inserted” table available within the Trigger that you can use to process all the records that are to be inserted.

    May be take a look at the BOL Topic “Using the inserted and deleted Tables” and the sample code in “Designing INSTEAD OF Triggers” for some pointers on using the Inserted table.

    Regards,

    John Marsh

    www.sql.lu
    SQL Server Luxembourg User Group

  • Jaime,

    As John said, triggers in SQL Server fire once per batch, so if your batch updates 1 row or 1 million rows the trigger fires only once. Try reading this article[/url] on triggers and if you have any questions post them here.

    Also if you post some table defintions, trigger code, and some sample data like outlined int eh link in my signature then someone will be able to present you with some specific ideas about how to go about your task.

  • Thank u guys for your attention. Well, here goes the code I tried (just 1 column for brevity 'sake):

    ALTER TRIGGER EvalLogUpdate

    ON dbo.EvalLog

    FOR INSERT

    AS

    DECLARE @gStudentID uniqueidentifier

    SELECT @gStudentID = StudentID FROM Inserted

    exec EvalLogUpdateSproc @gStudentID = @gStudentID

    ALTER PROCEDURE [dbo].[EvalLogUpdateSproc]

    @gStudentID uniqueidentifier

    AS

    UPDATE [dbo].[EvalLog] SET

    [StudentRemarks] = (SELECT StudentsLog.Remarks FROM ClassRemarks WHERE StudentID = @gStudentID)

    Like I said, this will update all StudentRemarks with the remarks from StudentID 1.

    I tried to add an extra where clause at the end of the procedure (in bold):

    ALTER PROCEDURE [dbo].[EvalLogUpdateSproc]

    @gStudentID uniqueidentifier

    AS

    UPDATE [dbo].[EvalLog] SET

    [StudentRemarks] = (SELECT StudentsLog.Remarks FROM ClassRemarks WHERE StudentID = @gStudentID)

    WHERE EvalLog.StudentID = @gStudentID

    But then only the first row in EvalLog is updated.

    Normally i'd solve this kind of problem doing a loop procedure on the client, but I was hoping for a better performing db-side solution.

    Regards,

    Jaime

  • In 2005 I see 3 (4) options in order of my preference:

    1. Move all your code into original insert process.

    2. Move the [dbo].[EvalLogUpdateSproc] code into the trigger using a join on the inserted table to get the student remarrks.

    3. Create a temporary table in the trigger (Select Into #temp from inserted) and then access the temporary table in [dbo].[EvalLogUpdateSproc] to get the student remarks.

    A possible offshoot of option 3 would be to populate an XML variable with the rows from inserted and pass it to [dbo].[EvalLogUpdateSproc].

  • Jack Corbett (4/28/2009)


    In 2005 I see 3 (4) options in order of my preference:

    2. Move the [dbo].[EvalLogUpdateSproc] code into the trigger using a join on the inserted table to get the student remarrks.

    This would seem like the best option to me, but how would I be able to define a join between inserted and Classremarks, since the latter is in a subquery?

  • I really think the best way is to put the logic into the code that is doing the insert. Why add the overhead of an update to the same table you are inserting into? It also puts all the logic in one place instead of "hiding" it in a trigger.

    If I were forced to do the trigger I'd do it something like this:

    IF OBJECT_ID('dbo.EvalLog') IS NOT NULL

    BEGIN

    DROP TABLE dbo.EvalLog

    END

    IF OBJECT_ID('dbo.ClassRemarks') IS NOT NULL

    BEGIN

    DROP TABLE dbo.ClassRemarks

    END

    CREATE TABLE dbo.EvalLog

    (

    EvalLogID INT IDENTITY(1,1),

    StudentID INT,

    StudentRemarks VARCHAR(10)

    )

    GO

    CREATE TABLE dbo.ClassRemarks

    (

    StudentID INT,

    Remarks VARCHAR(10)

    )

    GO

    CREATE TRIGGER EvalLogUpdate ON dbo.EvalLog

    FOR INSERT

    AS

    BEGIN

    SET NOCOUNT ON

    UPDATE [dbo].[EvalLog]

    SET [StudentRemarks] = CR.Remarks

    FROM

    dbo.EvalLog AS EL JOIN

    ClassRemarks CR ON

    EL.StudentId = CR.StudentId JOIN

    inserted AS I ON

    CR.StudentID = I.StudentID AND

    EL.EvalLogID = I.EvalLogId

    END

    GO

    INSERT INTO dbo.ClassRemarks (

    StudentID,

    Remarks

    )

    Select

    1,

    'Test 1'

    UNION ALL

    SELECT

    2,

    'Test 2'

    INSERT INTO dbo.evallog

    (

    StudentId

    )

    SELECT

    StudentId

    FROM

    dbo.ClassRemarks AS CR

    UNION ALL

    SELECT

    3

    UPDATE dbo.ClassRemarks

    SET Remarks = 'New Test 2'

    WHERE

    StudentID = 2

    INSERT INTO dbo.evallog

    (

    StudentId

    )

    SELECT

    StudentId

    FROM

    dbo.ClassRemarks AS CR

    SELECT * FROM dbo.EvalLog

  • Hi Jack, played a bit around with your suggestions, and I finally think the temp table approach will work better in my case, since I have all kinds of disparate data coming together in this update (that's why it can't be done during insert btw).

    Thanks a lot for helping me sort it out

    Regards,

    Jaime

  • Hi Jaime,

    I have some confusion in your code. here,

    ALTER PROCEDURE [dbo].[EvalLogUpdateSproc]

    @gStudentID uniqueidentifier

    AS

    UPDATE [dbo].[EvalLog] SET

    [StudentRemarks] = (SELECT StudentsLog.Remarks FROM ClassRemarks WHERE StudentID = @gStudentID)

    I think, you need to put where condition into above query, like below.

    UPDATE [dbo].[EvalLog] SET

    [StudentRemarks] = (SELECT StudentsLog.Remarks FROM ClassRemarks WHERE StudentID = @gStudentID)

    where StudentID=@gStudentID

    Please check.

    "Don't limit your challenges, challenge your limits"

  • kruti (4/29/2009)


    I think, you need to put where condition into above query, like below.

    UPDATE [dbo].[EvalLog] SET

    [StudentRemarks] = (SELECT StudentsLog.Remarks FROM ClassRemarks WHERE StudentID = @gStudentID))

    where StudentID=@gStudentID

    Hi Kruti, thanks for taking your time.

    Well a few posts up I already pointed out the bottom where clause, which also doesn't work, since it updates only the first row...

    Regards,

    premy

  • Hi Jaime,

    Sorry! consider it as my reply in hurry....... 😛

    "Don't limit your challenges, challenge your limits"

Viewing 11 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic. Login to reply