0

I have an UPDATE trigger that occurs when a record is inserted into a table but would like to create an INSERT at the same time the trigger is fired.

The original INSERT puts a record into the BatchQueue table and when this occurs the trigger is fired to update a second table [Call].

I want to be able to add a record in the BatchQueue table that is basically similar to the initial record being inserted but differs on the time columns and one other column. I could technically do it on the original insert but would need to do a WHEN or IF, for only when SFlags = 11

The original INSERT statement:

BEGIN
    INSERT INTO BatchQueue (TimeToExecute, Operation, 
    Parameter,RuleID, FilterID, SFlags)
        SELECT @TimeToExecute, @Operation, @Parameter, @RuleID, @FilterID, 
        @SFlags FROM Call WHERE [ID]=@Parameter AND Active=0
               AND (OnlineCount>0 OR OnlineScreenCount>0 
       OR (Flags&POWER(2,26)=POWER(2,26)))  
 END

This is the insert I would like to do:

BEGIN
   INSERT INTO [dbo].[BatchQueue]
   VALUES(DateAdd(mi,2,getutcdate()),1,Call.ID,2,null,9,0,0,0)
   WHEN Call.SFlags = 11
END

The trigger statement:

BEGIN
IF @@ROWCOUNT > 0
BEGIN
   SET NOCOUNT ON
   UPDATE Call SET StoreReqCount = StoreReqCount + CallCount.actionCount
   FROM Call, (SELECT Parameter, [actionCount] = COUNT(*) FROM inserted 
   GROUP BY Parameter ) AS CallCount
   WHERE Call.ID = CallCount.Parameter
END

Can someone advise how best to do this? I hope I have clarified. To reiterate, either add the second INSERT to the first with the condition of SFlags=11 or do the insert with the trigger. Which is better?

EDIT:

Tried the following:

   SELECT @StoreActionID = [ID] FROM BatchQueue 
   WHERE Parameter=@Parameter AND RuleID=@RuleID AND 
    SFlags=@SFlags
   IF @StoreActionID IS NOT NULL
   BEGIN
     UPDATE BatchQueue SET FilterID = @FilterID WHERE [ID] = 
     @StoreActionID
   END
ELSE
BEGIN
   INSERT INTO BatchQueue (TimeToExecute, Operation, Parameter, 
      RuleID, FilterID, SFlags)
        SELECT @TimeToExecute, @Operation, @Parameter, @RuleID, 
     @FilterID, @SFlags FROM Call WHERE [ID]=@Parameter AND Active=0
               AND (OnlineCount>0 OR OnlineScreenCount>0 OR 
     (Flags&POWER(2,26)=POWER(2,26))) --bit26 indicates META-DATA-ONLY
END
-- ADDED ADDITIONAL INSERT TO INSERT ACTION BASED ON STOREFLAGS 
BEGIN
    IF @SFlags = 11
    BEGIN 
        INSERT INTO BatchQueue (TimeToExecute, Operation, Parameter, 
        RuleID, FilterID, SFlags)
        SELECT @TimeToExecute, @Operation, @Parameter, @RuleID, 
        @FilterID, 9 FROM Call WHERE [ID]=@Parameter AND Active=0
               AND (OnlineCount>0 OR OnlineScreenCount>0 OR 
        (Flags&POWER(2,26)=POWER(2,26))) --bit26 indicates META-DATA-ONLY
    END        
END
vbNewbie
  • 3,291
  • 15
  • 71
  • 155
  • Please clarify your question. Are you looking to modify your `INSERT INTO [dbo].[BatchQueue]` statement such that some of the values would come from `Call` table? If so, please specify the logic. – Alex Nov 12 '17 at 23:59
  • Thanks. I have tried to restate the question more clearly – vbNewbie Nov 13 '17 at 06:21
  • Are you looking to insert a second record (row) to BatchQueue when `Call.SFlags = 11`? or modify an existing record? – Alex Nov 13 '17 at 06:44
  • Add a second to row based on that condition. I have tried something but it did not work. will add in edit now. – vbNewbie Nov 13 '17 at 06:55
  • you have two options: do it in the trigger but you need to make sure direct trigger recursion is disabled (https://stackoverflow.com/a/1529516/6305294) - could be problematic if other code depends on it. – Alex Nov 13 '17 at 07:04
  • I also notice that you use variables a lot, is your trigger written to process single row inserts only? (See this article: https://www.mssqltips.com/sqlservertutorial/2911/working-with-triggers/) – Alex Nov 13 '17 at 07:09
  • thanks Alex. Yes I just realized the cascade effects of triggers so a bit weary of the effect of changing it. Thanks for the links will review first. Yes it does do single row insert only – vbNewbie Nov 13 '17 at 07:39

1 Answers1

1

One of the good options you can take is write a stored procedure, and within the stored procedure include the original INSERT statement and then the special INSERT into same table as first INSERT. But, only execute the special INSERT if the first INSERT was successful.

Let the UPDATE happen through your existing trigger. You don't want to disturb the trigger if its being used in production successfully.

Also,it would be good if you can wrap these two INSERTstatements within a transaction.

This will satisfy your requirement.

Put following T-SQL code into your stored precedure

SET NOCOUNT ON;
BEGIN TRY

 Declare @insertedID int;

  --original INSERT
  INSERT INTO BatchQueue (TimeToExecute, Operation,
  Parameter, RuleID, FilterID, SFlags)
    SELECT
      @TimeToExecute,
      @Operation,
      @Parameter,
      @RuleID,
      @FilterID,
      @SFlags
    FROM Call
    WHERE [ID] = @Parameter
    AND Active = 0
    AND (OnlineCount > 0
    OR OnlineScreenCount > 0
    OR (Flags & POWER(2, 26) = POWER(2, 26));

  Set @insertedID = scope_identity() ;

  ---- INSERT if a row is successfully inserted
  IF @@ROWCOUNT > 0
  BEGIN

    INSERT INTO [dbo].[BatchQueue]
      SELECT DATEADD(mi, 2, GETUTCDATE()), 1, @parameter, 2, NULL, 9, 0, 0, 0)  
      WHERE @SFlags = 11;

  END

  --commit tran
  IF @@trancount > 0
  BEGIN
    COMMIT TRAN
  END

END TRY

BEGIN CATCH
  --get error details, which you can log to some table
  DECLARE @ErrorMessage nvarchar(4000);
  DECLARE @ErrorSeverity int;
  DECLARE @ErrorState int;

  SELECT
    @ErrorMessage = ERROR_MESSAGE(),
    @ErrorSeverity = ERROR_SEVERITY(),
    @ErrorState = ERROR_STATE();

  --roll back tran
  IF @@trancount > 0
  BEGIN
    ROLLBACK TRAN
  END

END CATCH
Sunil
  • 20,653
  • 28
  • 112
  • 197
  • Thanks Sunil, will try this. How would you add an additional condition and change the insert to match the original insert rather than use all preset values? for example like I have in EDIT: If @SFlags = 11 I want to add if Call.onlinescreencount > 0 – vbNewbie Nov 13 '17 at 08:01
  • This does not seem to work and I think it has something to do with only allowing single row insert. I have updated the post to include the other statements in the stored procedure I did not include the first time that my impact this. – vbNewbie Nov 13 '17 at 08:12
  • Where are these variables coming from - `@TimeToExecute, @Operation, @Parameter, @RuleID, @FilterID, @SFlags and @Parameter`? Are these input parameters to your stored procedure? – Sunil Nov 13 '17 at 08:36
  • Also, can you use a simpler condition in place of `(Flags & POWER(2, 26) = POWER(2, 26)))`? – Sunil Nov 13 '17 at 08:48
  • I have removed a closing parethesis in your bitwise operator condition. Try the query now. – Sunil Nov 13 '17 at 08:50
  • The variables are coming from the table Call. Both statements are called from within the application (java code). These are input parameters. – vbNewbie Nov 13 '17 at 08:55
  • Ok. Try the query now since I have removed a parenthesis. – Sunil Nov 13 '17 at 08:55
  • I am understanding it now. Give me a few minutes to sort this out. – Sunil Nov 13 '17 at 08:57
  • I changed the second insert to match the original insert to avoid having default values in the procedure. Please see my edit and thanks for your time with this. It only inserts the first record. No problem. Once the first insert happens, if the sflags = 11 then do the second insert. – vbNewbie Nov 13 '17 at 08:59
  • In your query `(SELECT Parameter, [actionCount] = COUNT(*) FROM inserted GROUP BY Parameter )` do you get only one record or multiple records when you group by paramater the inserted records? – Sunil Nov 13 '17 at 09:02
  • I think the above complext query may not be needed. Instead just use `WHERE Call.ID = @Parameter` in UPDATE statement. – Sunil Nov 13 '17 at 09:06
  • I have made above change in UPDATE query. So, try now and please let me know. – Sunil Nov 13 '17 at 09:07
  • wrt your first question, only one record is returned for that trigger statement. – vbNewbie Nov 13 '17 at 09:15
  • Then try the changed query now. – Sunil Nov 13 '17 at 09:19
  • so you think its better to do the insert with the trigger? – vbNewbie Nov 13 '17 at 09:22
  • No. You should not use trigger. A stored procedure is the best approach. Stored procedures are visible and when issues happen, its easy for a developer to see what's happening. A trigger on the other hand can cause hard to debug issues. – Sunil Nov 13 '17 at 09:25
  • Ok then sorry one more question. When do I call this stored procedure then? Because the original insert is in a stored procedure and I am not sure I will be allowed to remove it. – vbNewbie Nov 13 '17 at 09:30
  • Can you not change that existing stored procedure to what is given here? – Sunil Nov 13 '17 at 09:32
  • If you can send me the original stored procedure in a chat room then I can put the necessary statements in that procedure. – Sunil Nov 13 '17 at 09:33
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/158842/discussion-between-vbnewbie-and-sunil). – vbNewbie Nov 13 '17 at 09:56
  • Just changed the query for special insert. Use this one. – Sunil Nov 13 '17 at 11:18