使用“WHERE CURRENT OF”子句仅更新CURSOR在SQL中定位的特定行

时间:2013-09-02 14:39:47

标签: sql sql-server tsql cursor

我在SQL中有以下光标:

DECLARE @Script varchar(max)

DECLARE @getScript CURSOR

SET @getScript = CURSOR FOR

SELECT [Script]
FROM ScriptTable

OPEN @getScript
FETCH NEXT
FROM @getScript INTO @Script

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        EXEC(@Script) --Working part.  This executes the query stored in the Script column.
                      --For example INSERT INTO zTest VALUES(VAL1, VAL2, etc etc..)

        UPDATE ScriptTable
        SET DateDone = GETDATE(), IsDone = 1, Err = NULL
        FETCH NEXT
        FROM @getScript INTO @Script 
    END TRY
    BEGIN CATCH
        DECLARE @Err varchar(max)
        SET @Err = ERROR_MESSAGE()

        UPDATE ScriptTable
        SET DateDone = GETDATE(), Err = @Err

    END CATCH
END

CLOSE @getScript
DEALLOCATE @getScript

Q1: 目前,我在执行EXEC(@Script)时将值插入到注释中指定的“zTest”表中。

但是,“更新ScriptTable”的第二部分更新了我的脚本表中的所有行。我知道我需要为光标移动的相应行指定ID。问题是,我该怎么做?我不想只更新相应的行,移到下一行然后更新那一行。

Q2: 我的下一个问题是,在CATCH块中,我认为一旦ScriptTable的脚本列中的一个查询出现错误,我就会创建一个无限循环,就像我查看结果一样,它只是继续前进和前进。我不想破坏;这个过程因为我想把错误写入Err列并继续下一行直到它到达@Script的末尾,然后停止。

IDENT_CURRENT,Scope_Identity等不起作用,因为我没有在脚本表中插入任何内容。

请帮忙。

3 个答案:

答案 0 :(得分:2)

关于Q1,你必须有一个主键才能使用光标进行更新(虽然有解决方法)。
一般来说,你会想要这样的语法:

update ScriptTable
 SET DateDone = GETDATE(), IsDone = 1, Err = NULL
where ID of @getScript

关于Q2,它是无限循环的意义。当您使用TRYCATCH子句但它失败时,它不会执行TRY“区域中的任何语法”。 因此,FETCH NEXT被跳过,并且在下一个循环中再次发生相同的错误 尽量确保循环中始终有FETCH NEXT

希望这会对你有所帮助。

答案 1 :(得分:1)

如果有兴趣的话,这是我的最终代码:

DECLARE @Script varchar(max)

        DECLARE @getScript CURSOR

        SET @getScript = CURSOR FOR

        SELECT [Script]
        FROM ScriptControl

        OPEN @getScript
        FETCH NEXT
        FROM @getScript INTO @Script

        DECLARE @Counter int = 1
        WHILE @@FETCH_STATUS = 0
        BEGIN
            BEGIN TRY
                EXEC(@Script)

                    UPDATE ScriptControl 
                    SET DateDone = GETDATE(), IsDone = 1, Error = NULL WHERE ID = @Counter

                FETCH NEXT
                FROM @getScript INTO @Script 

                SET @Counter = (@Counter + 1)
            END TRY
            BEGIN CATCH
                DECLARE @Err varchar(max)
                SET @Err = ERROR_MESSAGE()

                UPDATE ScriptControl 
                SET CSC_EOD_DateDone = NULL, CSC_EOD_Err = @Err, CSC_EOD_IsDone = 0 WHERE CURRENT OF @getScript

                FETCH NEXT
                FROM @getScript INTO @Script

                SET @Counter = (@Counter + 1)
            END CATCH
        END

        CLOSE @getScript
        DEALLOCATE @getScript

答案 2 :(得分:1)

此:

DECLARE @ScriptControlId INT, @Script VARCHAR(MAX)

DECLARE @getScript CURSOR
SET @getScript = CURSOR FOR
SELECT [ID], [Script]
FROM ScriptControl

OPEN @getScript
FETCH NEXT
FROM @getScript INTO @ScriptControlId, @Script

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        EXEC(@Script)

        UPDATE ScriptControl 
        SET DateDone = GETDATE(), IsDone = 1, Error = NULL
        WHERE ID = @ScriptControlId

        FETCH NEXT FROM @getScript INTO @ScriptControlId, @Script
    END TRY
    BEGIN CATCH
        DECLARE @Err VARCHAR(MAX) = ERROR_MESSAGE()

        UPDATE ScriptControl 
        SET DateDone = NULL, Error = @Err, IsDone = 0
        WHERE CURRENT OF @getScript

        FETCH NEXT FROM @getScript INTO @ScriptControlId, @Script
    END CATCH
END

CLOSE @getScript
DEALLOCATE @getScript

或者这个:

DECLARE @Script VARCHAR(MAX)

DECLARE @getScript CURSOR
SET @getScript = CURSOR FOR
SELECT [Script]
FROM ScriptControl

OPEN @getScript
FETCH NEXT
FROM @getScript INTO @Script

WHILE @@FETCH_STATUS = 0
BEGIN
    BEGIN TRY
        EXEC(@Script)

        UPDATE ScriptControl 
        SET DateDone = GETDATE(), IsDone = 1, Error = NULL
        WHERE CURRENT OF @getScript

        FETCH NEXT FROM @getScript INTO @Script
    END TRY
    BEGIN CATCH
        DECLARE @Err VARCHAR(MAX) = ERROR_MESSAGE()

        UPDATE ScriptControl 
        SET DateDone = NULL, Error = @Err, IsDone = 0
        WHERE CURRENT OF @getScript

        FETCH NEXT FROM @getScript INTO @Script
    END CATCH
END

CLOSE @getScript
DEALLOCATE @getScript