Search code examples
triggershana

how to show error meassage using trigger in SAP HANA


I’m trying to create a trigger such as whenever I insert a new record in the Sales table, the Product table should update is “Inventory” based on Sales table “quantity”:

 Product table      Sales table
P_ID|QTY  |        |P_ID|QTY   |
1   |10   |        |1   |5     |
2   |15   |        

Code:

create trigger "KABIL_PRACTICE"."SALES_TRIGGER" 
after insert on "KABIL_PRACTICE"."SALES" REFERENCING NEW ROW AS newrow for each row
begin 
update "KABIL_PRACTICE"."Inventory" set "Inventory" = "Inventory" - :newrow.QTY 
where "P_ID" = :newrow.P_ID ;
end;

I get the expected result when I insert a record into the Sales table with P-ID 1 and quantity 5:

 updated Product table          Sales table
P_ID|QTY  |                    |P_ID|QTY   |
1   |5    |                    |1   |5     |
2   |15   |                    |1   |5     |

But if I insert a record into the Sales table again with P_ID 1 and quantity 6, the Sales table quantity is more than the available inventory quantity means it goes to negative value...

 updated Product table          Sales table
P_ID|QTY  |                    |P_ID|QTY   |
1   |-1   |                    |1   |5     |
2   |15   |                    |1   |5     |
                               |1   |6     |

I just want to intimate sales order quantity value is higher than available inventory quantity and it should not go to negative values... is there is any way to this...

I tried this code:

create trigger "KABIL_PRACTICE"."SALES_UPDATE_TRIGGER" 
before insert on "KABIL_PRACTICE"."SALES" REFERENCING NEW ROW AS newrow for each row
begin 

if("Inventory" > :newrow.QTY )
Then
update "KABIL_PRACTICE"."Inventory" set "Inventory" = "Inventory" - :newrow.QTY 
where "P_ID" = :newrow.P_ID ;
elseif ("Inventory" < :newrow.QTY )
Then  NULL;

delete "KABIL_PRACTICE"."SALES" where "QTY" = 0;
end;

Solution

  • The problem you have here is a classic. Usually the two business processes "SALES" and "ORDER FULFILLMENT" are separated, so the act of selling something would not have an immediate effect on the stock level. Instead, the order fulfilment could actually use other resources (e.g. back ordering from another vendor or producing more). That way the sale would be de-coupled from the current stock levels.

    Anyhow, if you want to keep it a simple dependency of "only-sell-whats-available-right-now" then you need to consider the following:

    • multiple sales could be going on at the same time
    • what to do with sales that can only be partly fulfilled, e.g. should all available items be sold or should the whole order be handled as not able to fulfil?

    To address the first point, again, different approaches can be taken. The easiest probably is to set a lock on the inventory records you are interested in as long as you make the decision(s) whether to process the order (and inventory transaction) or not.

    SELECT QTY "KABIL_PRACTICE"."Inventory" WHERE P_ID = :P_ID FOR UPDATE;
    

    This statement will acquire a lock on the relevant row(s) and return or wait until the lock gets available in case another session already holds it.

    Once the quantity of an item is retrieved, you can call the further business logic (fulfil order completely, partly or decline).
    Each of these application paths could be a stored procedure grouping the necessary steps. By COMMITing the transaction the lock will get released.

    As a general remark: this should not be implemented as triggers. Triggers should generally not be involved in application paths that could lead to locking situations in order to avoid system hang situations. Also, triggers don't really allow for a good understanding of the order in which statements get executed, which easily can lead to unwanted side effects.

    Rather than triggers, stored procedures can provide an interface for applications to work with your data in a meaningful and safe way. E.g.

    • procedure ProcessOrder

      • for each item in order
        • check stock and lock entry
      • (depending on business logic):
      • subtract all available items from stock to match order as much as possible
      • OR: only fulfil order items that can be fully provided and mark other items as not available. Reduce sales order SUM.
      • OR: decline the whole order.

      • COMMIT;

    Your application can then simply call the procedure and take retrieve the outcome data (e.g. current order data, status,...) without having to worry about how the tables need to be updated.