SQL Triggers and recursion

Preventing Recursive Trigger Conditions

In the past, I have written on some of the possibilities of using triggers in SQL.  SQL triggers can be very useful, but there are conditions that you have to watch out for when writing them.  There may be times when you want to update one column of a table, when a row of that table is updated.  If you are not careful you can end up with a recursive condition, where the trigger keeps firing over and over.

If, for example, let’s assume that you have TABLEA, with ITEM_NO, QTY_ON_HAND, COST, and INVENTORY_VALUE.  While good programming practices dictate that computed values are not normally stored, for our purposes assume that INVENTORY_VALUE is COST multiplied by QTY_ON_HAND.  It is very tempting to write an UPDATE trigger on TABLEA, so that when the QTY_ON_HAND or COST change, the INVENTORY_VALUE is updated.

The simple approach to this (ignoring the details of cursor loops, etc.) would be add an UPDATE trigger on TABLEA, that declares the local variable @ItemNo, and a cursor for:

     select ITEM_NO
       from INSERTED

then do a cursor loop into @ItemNo.  Then, inside your cursor loop, do:

     UPDATE TABLEA set INVENTORY_VALUE=QTY_ON_HAND*COST where ITEM_NO=@ItemNo

The problem here, is that when a record is updated, the trigger will fire, which will update the record and fire the trigger, again.  In other words, the trigger will fire repeatedly, until it aborts when the maximum recursion depth is reached.

The trick, is to add conditions to the cursor declaration, so that records that do not need updated are not selected.  In this case, if the QTY_ON_HAND and COST have not changed, the record does not need to be updated:

     select ITEM_NO
       from INSERTED I
       join DELETED D on D.ITEM_NO=I.ITEM_NO
      where D.QTY_ON_HANDI.QTY_ON_HAND or
            D.COSTI.COST

The result is that only the records are selected where either the quantity, or cost, have changed.  So, if the quantity changes, the INVENTORY_VALUE is recalculated, which fires the trigger again.  However, the second time it fires, neither the quantity nor cost have changed, and it does not update the record again.

 

Leave a Reply