【问题标题】:cursors within cursors for Auto_Fix usersAuto_Fix 用户的游标内的游标
【发布时间】:2014-10-29 16:01:29
【问题描述】:

我有以下脚本,我希望能够针对除系统数据库之外的数据库的动态列表运行它。这已经够直截了当了。棘手的一点是每个数据库可能有不同的用户列表来运行修复命令。这会是第三个光标吗?我在下面的尝试没有正确填充每个数据库的用户。任何帮助将不胜感激。

SET nocount ON
GO
SET QUOTED_IDENTIFIER OFF
GO
--
-- Declare and define variables
--

DECLARE @databasename VARCHAR(50) -- database name
DECLARE @sqlcommand nvarchar(256) -- SQL Command generated

-- 在@name 中包含范围内的数据库名称

DECLARE db_cursor CURSOR FOR
  SELECT NAME
  FROM   master.dbo.sysdatabases
  WHERE  NAME NOT IN ( 'master', 'model', 'msdb', 'tempdb', 'DBATools' ) -- don't include the databases
OPEN db_cursor

FETCH NEXT FROM db_cursor INTO @databasename

WHILE @@FETCH_STATUS = 0
  BEGIN
      PRINT 'Fixing Logins for '
            + Cast(@databasename AS VARCHAR)

      DECLARE curSQL CURSOR FOR
        SELECT "USE " + ( @databasename ) + ";" + " exec sp_change_users_login 'AUTO_FIX','" + NAME + "'"

      SELECT NAME
      FROM   sys.sysusers
      WHERE  issqluser = 1
             AND NAME NOT IN ( 'dbo', 'guest', 'INFORMATION_SCHEMA', 'sys' )

      OPEN curSQL

      FETCH curSQL INTO @sqlcommand

      WHILE @@FETCH_STATUS = 0
        BEGIN
            PRINT @sqlcommand
            EXEC (@sqlcommand)
            FETCH curSQL INTO @sqlcommand
        END

      CLOSE curSQL
      DEALLOCATE curSQL

      FETCH NEXT FROM db_cursor INTO @databasename
  END

CLOSE db_cursor

DEALLOCATE db_cursor 

【问题讨论】:

  • 我认为您应该将特定的数据库标签添加到您的问题中。我猜是 SQLServer ?

标签: sql sql-server tsql cursors


【解决方案1】:

或者你可以不用光标。

DECLARE @Output NVARCHAR(MAX)
SET @Output = ''

SELECT @Output = @Output +
'--Fixing Logins For ' + name + CHAR(10) + 
'USE ' + name + CHAR(10) + 
'EXEC sp_change_users_login ''AUTO_FIX'','''+
(
    SELECT  b.name 
    FROM   sys.sysusers as b
    WHERE  issqluser = 1
    AND b.name NOT IN ( 'dbo', 'guest', 'INFORMATION_SCHEMA', 'sys' )
)
+''''+CHAR(10)+CHAR(10)

FROM  master.dbo.sysdatabases
WHERE  NAME NOT IN ( 'master', 'model', 'msdb', 'tempdb', 'DBATools' )
PRINT @Output

【讨论】:

    【解决方案2】:

    您的过程的主要内容是,与 PHP 不同,TSQL 不能互换使用单引号和双引号。所以我修复了你的动态 SQL 字符串。

    另一个小问题似乎是游标声明中的脱节查询 - 在您的声明中,您使用 select 子句跟随第二个声明,没有伴随的 from 子句,这将引发“名称”无法为该游标找到。所以我也解决了这个问题。

    DECLARE @databasename SYSNAME, @sqlcommand nvarchar(max)
    DECLARE db_cursor CURSOR FOR
        SELECT NAME
        FROM   master.dbo.sysdatabases
        WHERE  NAME NOT IN ( 'master', 'model', 'msdb', 'tempdb', 'DBATools' ) -- don't include the databases
    OPEN db_cursor
    
    FETCH NEXT FROM db_cursor INTO @databasename
    
    WHILE @@FETCH_STATUS = 0
    BEGIN
        PRINT 'Fixing Logins for '
        + Cast(@databasename AS VARCHAR)
    
        DECLARE curSQL CURSOR FOR
            SELECT 'USE ' + @databasename + ';' + ' exec sp_change_users_login ''AUTO_FIX'',''' + NAME + ''';'
            FROM   sys.database_principals
            WHERE  Type='S'
                AND NAME NOT IN ( 'dbo', 'guest', 'INFORMATION_SCHEMA', 'sys' )
    
        OPEN curSQL
    
        FETCH curSQL INTO @sqlcommand
    
        WHILE @@FETCH_STATUS = 0
        BEGIN
            PRINT @sqlcommand
            --EXEC (@sqlcommand)
            FETCH curSQL INTO @sqlcommand
        END
    
        CLOSE curSQL
        DEALLOCATE curSQL
    
        FETCH NEXT FROM db_cursor INTO @databasename
    END
    
    CLOSE db_cursor
    
    DEALLOCATE db_cursor 
    

    编辑:根据评论将表切换到 database_principals 而不是 sys.sysusers。

    【讨论】:

    • 谢谢。根据我的尝试,这也存在问题。如果你运行它,你会注意到每个数据库的用户帐户都与当前在 ssms 的数据库下拉列表中选择的数据库一致。对于每个数据库,要固定的用户依次不同。该脚本需要能够枚举每个数据库的用户,然后将它们插入到修复字符串中。你能试试这个,让我知道你的想法。再次感谢。
    • 啊,那你需要 sys.database_principals,而不是 sys.sysusers。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多