1

I have an UPDATE statement I've written that will take a @CHANGE (positive or negative integer value) and update the CURRENT_INVENTORY for that type of item.

UPDATE ITEM_INVENTORY
SET    CURRENT_INVENTORY = MAX(CURRENT_INVENTORY + @CHANGE, 0),
       LAST_UPD_TSTAMP = CURRENT_TIMESTAMP,
       LAST_UPD_SOURCE = @SOURCE
WHERE  LOCATION = @LOCATION
       AND ITEM_TYPE = @ITEM_TYPE;

I'd like to know what CURRENT_INVENTORY is before and after I run this update. Is there a way to select both the OLD TABLE and FINAL TABLE value of CURRENT_INVENTORY?

I'm wanting to display a message along the lines of "{location} inventory changed from {old} to {new}". I could use a separate SELECT to get the old/current value, do the math in my code, and then UPDATE the row on the table. I believe that'd be susceptible to race conditions though (since the first SELECT won't lock the row) so I'm attempting to do it in a single query.

I don't think I can select both OLD and FINAL so I believe the best solutions I have are either:

  1. Select value from OLD TABLE and duplicate the logic from the CASE statement to derive the new value
  2. Select value from OLD TABLE and select the new value (within the same transaction now that my UPDATE has locked the row)

Is there a better/correct way to accomplish this?

Jeff B
  • 8,572
  • 17
  • 61
  • 140
  • 1
    Side note: DB2 allows the use of `MAX` as a scalar selector (you don't need `CASE`), and most others have an equivalent `GREATEST` as well. However.... negative inventory is usually actually a thing in retail, so I'm a little worried about what you're doing. It also makes the order in which you process updates extremely important, or you could end up reporting inventory you don't have (by selling inventory before it was entered into the system). – Clockwork-Muse Oct 16 '18 at 18:16
  • @Clockwork-Muse Ah, `MAX` is much better ;) This isn't for retail so we don't need the same level of rigorous correctness that environment requires. Great insight though! – Jeff B Oct 16 '18 at 19:00
  • So maybe also add `WHERE CURRENT_INVENTORY <> MAX(CURRENT_INVENTORY + @CHANGE,0)` to avoid updating a row when nothing has actually changed – Paul Vernon Oct 16 '18 at 22:39

2 Answers2

3

You can use "select from update" for that (SQL manual). Example:

SELECT EMPNO, SALARY, BONUS , OLD_SALARY , OLD_BONUS
    FROM FINAL TABLE
        (UPDATE EMP  INCLUDE  ( OLD_SALARY DECIMAL(9,2)
                              , OLD_BONUS DECIMAL(9,2))
        SET SALARY     = SALARY+1000
        ,   BONUS      = 0
        ,   OLD_SALARY = SALARY
        ,   OLD_BONUS  = BONUS
        WHERE SALARY > 28000);
Paul Vernon
  • 3,818
  • 1
  • 10
  • 23
Isaac
  • 71
  • 2
1

Updating inline view instead of table:

SELECT CURRENT_INVENTORY, CURRENT_INVENTORY_OLD
FROM FINAL TABLE(
  UPDATE (SELECT *, CURRENT_INVENTORY AS CURRENT_INVENTORY_OLD 
          FROM ITEM_INVENTORY)
  SET CURRENT_INVENTORY = CASE 
                             WHEN CURRENT_INVENTORY + @CHANGE < 0 THEN 0
                             ELSE CURRENT_INVENTORY + @CHANGE
                           END,
       LAST_UPD_TSTAMP = CURRENT_TIMESTAMP,
       LAST_UPD_SOURCE = @SOURCE
  WHERE LOCATION = @LOCATION
    AND ITEM_TYPE = @ITEM_TYPE
);
Lukasz Szozda
  • 162,964
  • 23
  • 234
  • 275
  • Got an error `ERROR [42601] [IBM][DB2] SQL0104N An unexpected token "(" was found following "". Expected tokens may include: " STATISTICS"`. I'm assuming updating an inline view is maybe not supported in DB2. – Jeff B Oct 16 '18 at 15:59
  • @JeffBridgman Maybe adding alias would help: `UPDATE (...) i ...` – Lukasz Szozda Oct 16 '18 at 16:00
  • Still get the same error. Thanks for the help though! The other answer seems to do the trick. – Jeff B Oct 16 '18 at 16:05
  • 1
    What version of Db2 are you using? The code above works for me on Db2 LUW 11.1.3.3. But then, the code in the other answer also works, and is maybe a touch nicer – Paul Vernon Oct 16 '18 at 16:10
  • DB2 for z/OS 11 I think (`SYSIBM.VERSION` return DSN11015 according to this [answer](https://stackoverflow.com/a/42233900/945456)) – Jeff B Oct 16 '18 at 16:59