I’m writing a stored procedure to update multiple records based on a table variable parameter.
The existing table is: Tb_Project_Image with relevant columns:
id PK (identity 1,1)
cat_ord decimal(4,2)
The procedure will receive a temporary table variable (shown in the code below) containing the id as PI_ID, and the new value for cat_ord as newCatOrd. idx is a simple identity for each row containing 1…n where n is the rowcount of @tempTable.
For each row in @tempTable, I want to update Tb_Project_Image where id = PI_ID to the corresponding value.
DECLARE @tempTable table (
idx smallint Primary Key IDENTITY(1,1),
PI_ID bigint,
newCatOrd decimal(4, 2) not null )
INSERT INTO @tempTable values (3, 7.01)
INSERT INTO @tempTable values (4, 7.02)
INSERT INTO @tempTable values (5, 7.03)
--etc...
DECLARE @error int
DECLARE @update int
DECLARE @iter int
SET @iter = 1
BEGIN TRAN
WHILE @iter <= (select COUNT(*) from @tempTable)
BEGIN
UPDATE Tb_Project_Image
SET cat_ord = (SELECT newCatOrd FROM @tempTable
WHERE idx = @iter)
WHERE id = (SELECT PI_ID FROM @tempTable
WHERE idx = @iter)
--error checking
set @error = @@ERROR
set @update = @@ROWCOUNT
IF ((@error = 0) AND (@update = 1))
BEGIN
SET @iter = @iter + 1
CONTINUE
END
ELSE
BREAK
END
IF ((@error = 0) AND (@update = 1))
COMMIT TRAN
ELSE
ROLLBACK TRAN
GO
Now, the error checking is because, to ensure integrity, EACH row in the temporary table MUST make 1 update. (explanation omitted to save space) If a single iteration of the while loop threw an error, or didn’t effect exactly 1 row, I want to break the loop and rollback the transaction
THE PROBLEM I’m having is that this error checking is not working. I’m currently running it with 14 rows in @tempTable and the 11th uses a PI_ID not found in the Project_Image table. Therefore, @update = 0... but it continues the loop and commits the data.
I’d be doubly glad if someone had a method of doing this that only used a single update statement.
You cannot do it this way, because even SET resets the state of @@ERROR and @@ROWNUMBER variables. In this case @@ROWCOUNT is set to 1 after
set @error = @@ERROR. If you do not assign the values to local variables, your code will work:But you might rather try try…catch error handling and test @@rowcount separately after update.
UPDATE: doing it in single update: