I have the following statement in my code
INSERT INTO #TProductSales (ProductID, StockQTY, ETA1)
VALUES (@ProductID, @StockQTY, @ETA1)
I want to do something like:
IF @ProductID exists THEN
UPDATE #TProductSales
ELSE
INSERT INTO #TProductSales
Is there a way I can do this?
I personally like to make a table variable or temp table to store the values and then do my update/insert, but I'm normally doing mass insert/updates. That is the nice thing about this pattern is that it works for multiple records without redundancy in the inserts/updates.
The pattern is (without error handling):
You don't need to perform an additional read of the #temp table here. You're already doing that by trying the update. To protect from race conditions, you do the same as you'd protect any block of two or more statements that you want to isolate: you'd wrap it in a transaction with an appropriate isolation level (likely serializable here, though that all only makes sense when we're not talking about a #temp table, since that is by definition serialized).
You're not any further ahead by adding an
IF EXISTS
check (and you would need to add locking hints to make that safe / serializable anyway), but you could be further behind, depending on how many times you update existing rows vs. insert new. That could add up to a lot of extra I/O.People will probably tell you to use
MERGE
(which is actually multiple operations behind the scenes, and also needs to be protected with serializable), I urge you not to. I lay out why here:For a multi-row pattern (like a TVP), I would handle this quite the same way, but there isn't a practical way to avoid the second read like you can with the single-row case. And no,
MERGE
doesn't avoid it either.Well, I guess there is a way to do it, but I haven't tested this thoroughly:
In either case, you perform the update first, otherwise you'll update all the rows you just inserted, which would be wasteful.
You could use something like: