我正在编写一个存储过程来根据表变量参数更新多个记录。
现有表格是: Tb_Project_Image 及相关列:
id PK (identity 1,1)
cat_ord decimal(4,2)
该过程将收到一个临时表变量(如下面的代码所示),其中包含PI_ID
的ID,cat_ord
的新值为newCatOrd
。 idx
是包含1 ... n的每一行的简单标识,其中n是@tempTable
的行数。
对于@tempTable
中的每一行,我想将Tb_Project_Image
id = PI_ID
更新为相应的值。
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
现在,错误检查是因为,为了确保完整性,临时表中的每一行必须进行1次更新。 (省略说明以节省空间)如果while循环的单次迭代引发错误,或者没有完全影响1行,我想打破循环并回滚事务
我遇到的问题是此错误检查无效。我目前在@tempTable
中使用14行运行它,而第11行使用PI_ID
表中未找到的Project_Image
。因此,@update = 0...
但它会继续循环并提交数据。
如果某人有一个只使用一个更新语句的方法,我会感到非常高兴。
答案 0 :(得分:3)
你不能这样做,因为即使SET也会重置@@ ERROR和@@ ROWNUMBER变量的状态。在这种情况下,@ {ROWCOUNT在set @error = @@ERROR
之后设置为1。如果不将值分配给局部变量,则代码将起作用:
IF ((@@error = 0) AND (@@rowcount = 1))
但您可能宁愿尝试try...catch error handling并在更新后单独测试@@ rowcount。
更新:在单次更新中执行此操作:
UPDATE t
SET cat_ord = tt.newCatOrd
FROM Tb_Project_Image t
INNER JOIN @tempTable tt
ON t.id = tt.PI_ID
-- If there was PI_ID not found in Tb_Project_Image
-- But I think that this should have been dealt with
-- During the initial loading of temporary table
IF @@ROWCOUNT <> (select count (*) from @tempTable)
BEGIN
-- Error reporting here
ROLLBACK TRANSACTION
END