从表变量更新表中的多行

时间:2012-08-01 22:37:47

标签: sql sql-server-2008

我正在编写一个存储过程来根据表变量参数更新多个记录。

现有表格是: Tb_Project_Image 及相关列:

id PK (identity 1,1) 
cat_ord decimal(4,2)

该过程将收到一个临时表变量(如下面的代码所示),其中包含PI_ID的ID,cat_ord的新值为newCatOrdidx是包含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...但它会继续循环并提交数据。

如果某人有一个只使用一个更新语句的方法,我会感到非常高兴。

1 个答案:

答案 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