又一个“光标只读”。

时间:2016-06-29 02:21:44

标签: sql-server tsql sql-server-2012

我的问题与其他问题不同,因为我真的需要一个游标来重建多个索引。但是,我想利用我已经在光标处并进行更新的事实。

这是SQL代码:

USE [MyDB]
DECLARE @TableName NVARCHAR(128)
DECLARE @IndexName NVARCHAR(128)
DECLARE @Sql NVARCHAR(MAX)

BEGIN TRY 
    DECLARE c CURSOR LOCAL FORWARD_ONLY KEYSET SCROLL_LOCKS FOR
    SELECT TableName,IndexName
    FROM _NonClusteredIndices_ i
    JOIN _Candidates_ c ON i.ObjectId = c.ObjectId
    WHERE State = 1
    ORDER BY TableName,IndexName
    FOR UPDATE OF i.State
    OPEN c
    FETCH NEXT FROM c INTO @TableName,@IndexName
    WHILE @@FETCH_STATUS = 0
    BEGIN
        SET @Sql = 'ALTER INDEX [' + @IndexName + '] ON [' + @TableName + '] REBUILD'
        EXEC(@Sql)
        UPDATE _NonClusteredIndices_ SET State = 2 WHERE CURRENT OF c
        FETCH NEXT FROM c INTO @TableName,@IndexName
    END
    CLOSE c
    DEALLOCATE c
END TRY
BEGIN CATCH
    SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() as ErrorState,
        ERROR_PROCEDURE() as ErrorProcedure,
        ERROR_LINE() as ErrorLine,
        ERROR_MESSAGE() as ErrorMessage;
END CATCH

唉,我得到光标只读

为什么呢?我该如何解决?

编辑

两个表的DDL是:

USE [MyDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[_Candidates_](
    [ObjectId] [int] NOT NULL,
    [ClientIdColumnId] [int] NOT NULL,
    [TableName] [nvarchar](128) NOT NULL,
    [ClientIdColumnName] [nvarchar](128) NOT NULL,
    [RowCount] [bigint] NOT NULL
) ON [PRIMARY]

CREATE TABLE [dbo].[_NonClusteredIndices_](
    [ObjectId] [int] NOT NULL,
    [IndexName] [nvarchar](128) NOT NULL,
    [State] [int] NOT NULL DEFAULT ((0))
) ON [PRIMARY]

(哎呀,列出错误的表格)

除了_NonClusteredIndices_.State列的默认约束

之外,没有任何表具有任何索引或约束

1 个答案:

答案 0 :(得分:1)

如果CURSOR引用的其中一个表没有唯一索引,则CURSOR将转换为STATICSTATIC游标是READ-ONLY。有关详细信息,请参阅Using Implicit Cursor Conversions

作为替代方案,我建议您完全摆脱CURSOR并使用基于集合的查询执行此操作:

DECLARE @sql NVARCHAR(MAX) = '';

BEGIN TRY
    BEGIN TRANSACTION
        SELECT 
            @sql = @sql + 'ALTER INDEX ' + QUOTENAME(IndexName) + ' ON ' + QUOTENAME(TableName) + ' REBUILD;' + CHAR(10)
        FROM _NonClusteredIndices_ i
        JOIN _Candidates_ c 
            ON i.ObjectId = c.ObjectId
        WHERE State = 1;

        EXEC(@sql);

        UPDATE i
            SET i.State = 2
        FROM _NonClusteredIndices_ i
        JOIN _Candidates_ c 
            ON i.ObjectId = c.ObjectId
        WHERE State = 1;

    COMMIT TRANSACTION
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0 BEGIN
        ROLLBACK TRANSACTION
    END
    DECLARE
        @ErrorNumber    INT,
        @ErrorMessage   NVARCHAR(4000),
        @ErrorState     INT,
        @ErrorSeverity  INT,
        @ErrorLine      INT;

    SELECT
        @ErrorNumber    =   ERROR_NUMBER(),
        @ErrorSeverity  =   ERROR_SEVERITY(),
        @ErrorState     =   ERROR_STATE(),
        @ErrorLine      =   ERROR_LINE(),
        @ErrorMessage   =   ERROR_MESSAGE();

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH