游标内的游标,用于数据库相关权限

Cursor within a cursor for database dependent permissions

我的代码似乎应该可以工作,但是测试表明来自内部游标的所有结果都基于脚本执行时的当前数据库,而不依赖于脚本中的 USE 语句。 我忘记了什么?

DECLARE @Debug      BIT          = 1
DECLARE @newgrp VARCHAR(100) = 'ChangeTrakingViewableRole'
DECLARE @obj        VARCHAR(100)
DECLARE @tsql       VARCHAR(900)
DECLARE @tsql2      VARCHAR(900)
DECLARE @msg        VARCHAR(900)
DECLARE @SchName    VARCHAR(55)
DECLARE @TblName    sysname
IF @Debug = 'TRUE' PRINT 'Debuging ON'
IF COALESCE(@newgrp,'') = '' 
    BEGIN
        PRINT 'There was no DatabaseRole, User or Group Specified to take the place of the Public Role'
        SET NOEXEC ON
    END
ELSE 
    BEGIN
        DECLARE DbCursor CURSOR FOR
            SELECT 'USE '+DB_NAME(database_id) FROM sys.change_tracking_databases
        OPEN DbCursor
        FETCH NEXT FROM DbCursor INTO @obj
        WHILE @@Fetch_Status = 0 
            BEGIN
                SET @tsql2 = @obj+'; '
                RAISERROR (@tsql2, 0, 1) WITH NOWAIT
                EXEC sp_sqlexec @tsql2
                -----------Commands within this next section are all database dependent
                BEGIN   --GRANT [VIEW CHANGE TRACKING] TO Change Tracking Enabled Tables
                    IF NOT EXISTS (SELECT name FROM sys.database_principals where name = @newgrp)
                        BEGIN
                            SET @tsql = N'CREATE ROLE '+@newgrp+' AUTHORIZATION [dbo]'
                            IF @Debug = 'TRUE'
                                BEGIN 
                                    SET @Msg = @tsql
                                    RAISERROR (@Msg, 0, 1) WITH NOWAIT
                                END 
                            ELSE
                                BEGIN 
                                    EXEC sp_sqlexec @tsql
                                END 
                        END
                    DECLARE TblCursor CURSOR FOR
                        SELECT sch.name, tbl.name
                        FROM sys.change_tracking_tables chg
                        JOIN sys.tables                 tbl ON chg.object_id=tbl.object_id
                        JOIN sys.schemas                sch ON tbl.schema_id=sch.schema_id
                        ORDER BY sch.name, tbl.name
                    OPEN TblCursor
                    FETCH NEXT FROM TblCursor INTO @SchName,@TblName
                    WHILE @@FETCH_STATUS = 0
                        BEGIN
                            SET @tsql = 'GRANT VIEW CHANGE TRACKING ON ['+@SchName+'].['+@TblName+'] TO '+@newgrp
                            IF @Debug = 'TRUE'
                                BEGIN 
                                    SET @Msg = @tsql
                                    RAISERROR (@Msg, 0, 1) WITH NOWAIT
                                END 
                            ELSE
                                BEGIN 
                                    EXEC sp_sqlexec @tsql
                                END 
                            FETCH NEXT FROM TblCursor INTO @SchName,@TblName
                        END
                    CLOSE TblCursor
                    DEALLOCATE TblCursor
                END
                FETCH NEXT FROM DbCursor INTO @obj
            END
        CLOSE DbCursor
        DEALLOCATE DbCursor
    END

外部游标中的 USE 语句对后面生成的语句没有任何作用,因为它们是独立执行的。当您的外部游标执行 USE 时,它只对第一个 EXEC sp_sqlexec 调用的范围有效;它不会更改整个脚本的数据库上下文。其余脚本的上下文 运行s 仍然是整个脚本的上下文,这意味着这些语句每次都会在当前数据库中得到 运行。

基本上,您需要更改它以生成一个脚本,其中包含您要在动态数据库上下文中从上到下执行的全部内容,USE 在顶部,然后执行该脚本只需一次调用 EXECsp_executesql.