我的问题与其他问题不同,因为我真的需要一个游标来重建多个索引。但是,我想利用我已经在光标处并进行更新的事实。
这是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
列的默认约束
答案 0 :(得分:1)
如果CURSOR
引用的其中一个表没有唯一索引,则CURSOR
将转换为STATIC
。 STATIC
游标是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