SQL Server - 如何将所有数据库的读取权限授予登录名?

Posted

技术标签:

【中文标题】SQL Server - 如何将所有数据库的读取权限授予登录名?【英文标题】:SQL Server - How to Grant Read Access to ALL databases to a Login? 【发布时间】:2011-03-06 10:53:42 【问题描述】:

我需要授予对服务器上所有 300 个数据库的新登录读取访问权限。如果不选中用户映射区域中的 300 个复选框,我该如何完成此操作?

【问题讨论】:

由于这是一个非常古老的问题,仍然有很多观点,请注意,在 SQL 2014+ 中,GRANT CONNECT ANY DATABASE TO <SQL_Login>;GRANT SELECT ALL USER SECURABLES TO <SQL_Login>; 将比旧的方法容易得多做事。 【参考方案1】:

一种方法是在 SSMS 的查询菜单上设置“结果为文本”,然后执行以下操作。

它实际上并没有进行更改,而是生成一个脚本供您查看和执行。

SET NOCOUNT ON;

DECLARE @user_name    SYSNAME
        , @login_name SYSNAME;

SELECT @user_name = 'user_name',
       @login_name = 'login_name'

SELECT '
    USE ' + QUOTENAME(NAME) + ';

    CREATE USER ' + QUOTENAME(@user_name)
       + ' FOR LOGIN ' + QUOTENAME(@login_name)
       + ' WITH DEFAULT_SCHEMA=[dbo];

    EXEC sys.sp_addrolemember
      ''db_datareader'',
      ''' + QUOTENAME(@user_name) + ''';

    EXEC sys.sp_addrolemember
      ''db_denydatawriter'',
      '''
       + QUOTENAME(@user_name) + '''; 

GO
'
FROM   sys.databases
WHERE  database_id > 4
       AND state_desc = 'ONLINE' 

或者你可以看看sys.sp_MSforeachdbas here或Aaron Bertrand的改进版here

如果您在运行此程序时没有看到所有字符,请打开“文本查询选项”并检查“每列中显示的最大字符数”的设置。确保将其设置为足够大的值以显示所有字符。

【讨论】:

为什么我现在才听说这个 sp_msforeachdb?我想我只是试着用我知道的工具弄清楚一切。好吧,我正在将它添加到工具箱中。谢谢! 谢谢!这似乎奏效了。我确实将该查询的结果复制到文本板中,并将 Go 替换为 \nGo\n @Greg - 很高兴它成功了。您是否在 Management Studio 中运行过它?如果是这样,选择“结果到文本”选项(CTRL + T)可能会避免中间步骤的需要。 默认 SQL 文本列限制为 256,因此您需要在查询 -> 查询选项 -> 结果 -> 文本中增加此限制,以避免生成的脚本被截断。 用户名和登录名周围的QUOTENAME 对我不起作用(SQL2019)。【参考方案2】:

您可以使用例如 Cursor,像这样:

USE master
GO

DECLARE @DatabaseName VARCHAR(32)   
DECLARE @SQL NVARCHAR(max)
DECLARE @User VARCHAR(64)
SET @User = '[SQL\srvSSISAcc]' --Your User

DECLARE Grant_Permission CURSOR LOCAL FOR
SELECT name FROM MASTER.dbo.sysdatabases
WHERE name NOT IN ('master','model','msdb','tempdb')  

OPEN Grant_Permission  
FETCH NEXT FROM Grant_Permission INTO @DatabaseName  
WHILE @@FETCH_STATUS = 0  
BEGIN  

    SELECT @SQL = 'USE '+ '[' + @DatabaseName + ']' +'; '+ 'CREATE USER ' + @User + 
    'FOR LOGIN ' + @User + '; EXEC sp_addrolemember N''db_datareader'', 
    ' + @User + '; EXEC sp_addrolemember N''db_datawriter'', ' + @User + ''

    EXEC sp_executesql @SQL
    PRINT @SQL

FETCH NEXT FROM Grant_Permission INTO @DatabaseName  
END  
CLOSE Grant_Permission  
DEALLOCATE Grant_Permission 

在我的帖子中找到有关此主题的更多信息: http://www.pigeonsql.com/single-post/2016/12/23/Grant-User-Access-to-All-Databases

【讨论】:

【参考方案3】:

我只需要一个可以访问所有具有数据读取权限的数据库的用户,所以我使用了以下代码: 顺便说一句,您需要运行查询的结果。

USE [master]
GO CREATE LOGIN [DOMAIN\USER] FROM WINDOWS WITH DEFAULT_DATABASE=[master] GO
select 'use ['+name+']
CREATE USER [DOMAIN\USER] FOR LOGIN [DOMAIN\USER]
EXEC sp_addrolemember N''db_datareader'', N''DOMAIN\USER''
'
from sys.databases

如果您不想将其应用于系统数据库,只需添加 其中database_id > 6

【讨论】:

【参考方案4】:

我不得不稍微调整一下 Martin Smith 的答案:

    空格和换行符导致并非所有文本都正确生成 Exec 语句中的 QUOTENAME 放在方括号中,这是不正确的。

我的版本:

SET NOCOUNT ON;

DECLARE @user_name    SYSNAME
        , @login_name SYSNAME;

SELECT @user_name = 'HelpdeskUser',
       @login_name = 'Helpdesk'

SELECT 'USE ' + QUOTENAME(NAME) + ';
        CREATE USER ' + QUOTENAME(@user_name)
       + ' FOR LOGIN ' + QUOTENAME(@login_name)
       + ' WITH DEFAULT_SCHEMA=[dbo];
    EXEC sys.sp_addrolemember ''db_datareader'',''' + @user_name + ''';
    EXEC sys.sp_addrolemember ''db_denydatawriter'', ''' + @user_name + '''; 
GO'
FROM   sys.databases
WHERE  database_id > 4
       AND state_desc = 'ONLINE' 

否则完美运行。 谢谢

【讨论】:

【参考方案5】:
EXEC sp_MSForEachDB 
'Declare @name varchar(100)
 select @name = ''?''
 PRINT @name
 IF db_id(@name) > 4
 BEGIN
 USE ?
 CREATE USER [user] FOR LOGIN [user];
EXEC sp_addrolemember ''db_datareader'', ''user''
 END'

【讨论】:

【参考方案6】:

使用一点 t-sql 浏览数据库并授予对每个数据库的访问权限。

我没有测试下面的代码。

DECLARE db_cursor CURSOR FOR
SELECT name 
FROM master.dbo.sysdatabases 
WHERE name NOT IN ('master','model','msdb','tempdb') 


WHILE @@FETCH_STATUS = 0  
BEGIN  

GRANT SELECT ON DATABASE::@name to 'username'; 

FETCH NEXT FROM db_cursor INTO @name  
END 

【讨论】:

在那之后使用的 t-sql 是我的困惑点。对此有任何指示吗?【参考方案7】:
Declare @Databases Cursor
Declare @DbName as nvarchar(64)
Declare @Sql nvarchar(max)
Declare @BaseAddUserSql nvarchar(max)
Declare @BaseAddRoleSql nvarchar(max)

Set @Databases = Cursor Fast_Forward For
    select [name]
    from master..sysdatabases
    where [name] not in('master','model','msdb','tempdb')

Open @Databases
Fetch Next From @Databases Into @DbName

Set @BaseAddUserSql = 'exec sp_adduser ''LOGINNAME'''
Set @BaseAddRoleSql = 'exec sp_addrolemember ''db_datareader'', ''LOGINNAME'''


While @@Fetch_Status = 0
Begin
    Begin Try
        Set @Sql = 'Use ' + Quotename(@DbName)
        exec (@Sql)

        Set @Sql = Replace(@BaseAddUserSql, 'LOGINNAME', <loginname>)
        exec(@Sql)

        Set @Sql = Replace(@BaseAddRoleSql, 'LOGINNAME', <loginname>)
        exec(@Sql)
    End Try
    Begin Catch
    End Catch

    Fetch Next From @Databases Into @DbName
End

Close @Databases
Deallocate @Databases

【讨论】:

它说它已成功完成,但我没有看到任何变化。用户映射区域没有改变。我为 输入的登录名在任何数据库中都不会以用户身份出现。有什么想法吗? @Greg - 您可能需要注释掉 Try-Catch 块以查看引发的错误。

以上是关于SQL Server - 如何将所有数据库的读取权限授予登录名?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Dapper 从 SQL Server Image 字段中读取 blob 数据?

如何读取、编辑和写入xls文件,然后导出到SQL Server

如何将SQL Server中多个表的数据一次性返回到一张EXCEL工作表(Sheet)中

SQL Server - 授予对所有现有和未来数据库的读取访问权限的登录权限

sql server 各种快照类型

如何将所有数据库(快速)自 sql server 2008 express 传递到 sql server 2008 R2(无 express)