如何编写 SQL 服务器数据库角色的脚本?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6300740/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-01 10:55:29  来源:igfitidea点击:

How to script SQL server database role?

sqlsql-servertsqlsql-server-2008

提问by Foster Geng

I need to make a script to copy one particular database role from one SQL server to another.

我需要编写一个脚本来将一个特定的数据库角色从一个 SQL 服务器复制到另一个。

Is there an easy way to generate a script that creates the role and all the role permissions?

是否有一种简单的方法来生成创建角色和所有角色权限的脚本?

回答by Alex Aza

You can get what you need with a script like this:

您可以使用这样的脚本获得所需的内容:

declare @RoleName varchar(50) = 'RoleName'

declare @Script varchar(max) = 'CREATE ROLE ' + @RoleName + char(13)
select @script = @script + 'GRANT ' + prm.permission_name + ' ON ' + OBJECT_NAME(major_id) + ' TO ' + rol.name + char(13) COLLATE Latin1_General_CI_AS 
from sys.database_permissions prm
    join sys.database_principals rol on
        prm.grantee_principal_id = rol.principal_id
where rol.name = @RoleName

print @script

回答by mcfea

I expanded on Mario Eis's answer:

我扩展了 Mario Eis 的回答:

SELECT 'GRANT ' + database_permissions.permission_name + ' ON ' + CASE database_permissions.class_desc
        WHEN 'SCHEMA'
            THEN '[' + schema_name(major_id) + ']'
        WHEN 'OBJECT_OR_COLUMN'
            THEN CASE 
                    WHEN minor_id = 0
                        THEN'['+OBJECT_SCHEMA_NAME(major_id) + '].' + '[' + object_name(major_id) + ']' COLLATE Latin1_General_CI_AS_KS_WS
                    ELSE (
                            SELECT object_name(object_id) + ' (' + NAME + ')'
                            FROM sys.columns
                            WHERE object_id = database_permissions.major_id
                                AND column_id = database_permissions.minor_id
                            )
                    END
        ELSE 'other'
        END + ' TO [' + database_principals.NAME + ']' COLLATE Latin1_General_CI_AS_KS_WS
FROM sys.database_permissions
JOIN sys.database_principals ON database_permissions.grantee_principal_id = database_principals.principal_id
LEFT JOIN sys.objects --left because it is possible that it is a schema
    ON objects.object_id = database_permissions.major_id
WHERE database_permissions.major_id > 0
    AND permission_name IN (
        'SELECT'
        ,'INSERT'
        ,'UPDATE'
        ,'DELETE'
        ,'EXECUTE'
        )

回答by John Eisbrener

I've made a pretty comprehensive script that not only scripts out all the permissions, but also all membership, and to put frosting on the cake formats the output for easy copy/pasting into a new query window. I've posted the script to my blogand update it from time-to-time, but below is the current version which should cover most bases:

我制作了一个非常全面的脚本,它不仅编写了所有权限,还编写了所有成员资格,并在蛋糕上添加了糖霜格式,以便轻松复制/粘贴到新的查询窗口中。我已将脚本发布到我的博客并不时更新它,但以下是当前版本,应涵盖大多数基础:

/********************************************************************
 *                                                                  *
 * Author: John Eisbrener                                           *
 * Script Purpose: Script out Database Role Definition              *
 * Notes: Please report any bugs to http://www.dbaeyes.com/         *
 *                                                                  *
 ********************************************************************/
DECLARE @roleName VARCHAR(255)
SET @roleName = 'DatabaseRoleName'

-- Script out the Role
DECLARE @roleDesc VARCHAR(MAX), @crlf VARCHAR(2)
SET @crlf = CHAR(13) + CHAR(10)
SET @roleDesc = 'CREATE ROLE [' + @roleName + ']' + @crlf + 'GO' + @crlf + @crlf

SELECT    @roleDesc = @roleDesc +
        CASE dp.state
            WHEN 'D' THEN 'DENY '
            WHEN 'G' THEN 'GRANT '
            WHEN 'R' THEN 'REVOKE '
            WHEN 'W' THEN 'GRANT '
        END + 
        dp.permission_name + ' ' +
        CASE dp.class
            WHEN 0 THEN ''
            WHEN 1 THEN --table or column subset on the table
                CASE WHEN dp.major_id < 0 THEN
                    + 'ON [sys].[' + OBJECT_NAME(dp.major_id) + '] '
                ELSE
                    + 'ON [' +
                    (SELECT SCHEMA_NAME(schema_id) + '].[' + name FROM sys.objects WHERE object_id = dp.major_id)
                        + -- optionally concatenate column names
                    CASE WHEN MAX(dp.minor_id) > 0 
                         THEN '] ([' + REPLACE(
                                        (SELECT name + '], [' 
                                         FROM sys.columns 
                                         WHERE object_id = dp.major_id 
                                            AND column_id IN (SELECT minor_id 
                                                              FROM sys.database_permissions 
                                                              WHERE major_id = dp.major_id
                                                                AND USER_NAME(grantee_principal_id) IN (@roleName)
                                                             )
                                         FOR XML PATH('')
                                        ) --replace final square bracket pair
                                    + '])', ', []', '')
                         ELSE ']'
                    END + ' '
                END
            WHEN 3 THEN 'ON SCHEMA::[' + SCHEMA_NAME(dp.major_id) + '] '
            WHEN 4 THEN 'ON ' + (SELECT RIGHT(type_desc, 4) + '::[' + name FROM sys.database_principals WHERE principal_id = dp.major_id) + '] '
            WHEN 5 THEN 'ON ASSEMBLY::[' + (SELECT name FROM sys.assemblies WHERE assembly_id = dp.major_id) + '] '
            WHEN 6 THEN 'ON TYPE::[' + (SELECT name FROM sys.types WHERE user_type_id = dp.major_id) + '] '
            WHEN 10 THEN 'ON XML SCHEMA COLLECTION::[' + (SELECT SCHEMA_NAME(schema_id) + '.' + name FROM sys.xml_schema_collections WHERE xml_collection_id = dp.major_id) + '] '
            WHEN 15 THEN 'ON MESSAGE TYPE::[' + (SELECT name FROM sys.service_message_types WHERE message_type_id = dp.major_id) + '] '
            WHEN 16 THEN 'ON CONTRACT::[' + (SELECT name FROM sys.service_contracts WHERE service_contract_id = dp.major_id) + '] '
            WHEN 17 THEN 'ON SERVICE::[' + (SELECT name FROM sys.services WHERE service_id = dp.major_id) + '] '
            WHEN 18 THEN 'ON REMOTE SERVICE BINDING::[' + (SELECT name FROM sys.remote_service_bindings WHERE remote_service_binding_id = dp.major_id) + '] '
            WHEN 19 THEN 'ON ROUTE::[' + (SELECT name FROM sys.routes WHERE route_id = dp.major_id) + '] '
            WHEN 23 THEN 'ON FULLTEXT CATALOG::[' + (SELECT name FROM sys.fulltext_catalogs WHERE fulltext_catalog_id = dp.major_id) + '] '
            WHEN 24 THEN 'ON SYMMETRIC KEY::[' + (SELECT name FROM sys.symmetric_keys WHERE symmetric_key_id = dp.major_id) + '] '
            WHEN 25 THEN 'ON CERTIFICATE::[' + (SELECT name FROM sys.certificates WHERE certificate_id = dp.major_id) + '] '
            WHEN 26 THEN 'ON ASYMMETRIC KEY::[' + (SELECT name FROM sys.asymmetric_keys WHERE asymmetric_key_id = dp.major_id) + '] '
         END COLLATE SQL_Latin1_General_CP1_CI_AS
         + 'TO [' + @roleName + ']' + 
         CASE dp.state WHEN 'W' THEN ' WITH GRANT OPTION' ELSE '' END + @crlf
FROM    sys.database_permissions dp
WHERE    USER_NAME(dp.grantee_principal_id) IN (@roleName)
GROUP BY dp.state, dp.major_id, dp.permission_name, dp.class

SELECT @roleDesc = @roleDesc + 'GO' + @crlf + @crlf

-- Display users within Role.  Code stubbed by Joe Spivey
SELECT  @roleDesc = @roleDesc + 'EXECUTE sp_AddRoleMember ''' + roles.name + ''', ''' + users.name + '''' + @crlf
FROM    sys.database_principals users
        INNER JOIN sys.database_role_members link 
            ON link.member_principal_id = users.principal_id
        INNER JOIN sys.database_principals roles 
            ON roles.principal_id = link.role_principal_id
WHERE   roles.name = @roleName

-- PRINT out in blocks of up to 8000 based on last \r\n
DECLARE @printCur INT
SET @printCur = 8000

WHILE LEN(@roleDesc) > 8000
BEGIN
    -- Reverse first 8000 characters and look for first lf cr (reversed crlf) as delimiter
    SET @printCur = 8000 - CHARINDEX(CHAR(10) + CHAR(13), REVERSE(SUBSTRING(@roleDesc, 0, 8000)))

    PRINT LEFT(@roleDesc, @printCur)
    SELECT @roleDesc = RIGHT(@roleDesc, LEN(@roleDesc) - @printCur)
END

PRINT @RoleDesc + 'GO'

Of note, you may run into a situation where the sp_AddRoleMember system sp adds user(s) to the DB that wasn't previously there. In this case, even though the user(s) is added, they are NOT granted the CONNECT permission, and any connection attempt made by said user or group will generate a user login error. To rectify this issue, you need to execute the following per new user/group within the db:

值得注意的是,您可能会遇到 sp_AddRoleMember 系统 sp 将用户添加到以前不存在的数据库的情况。在这种情况下,即使添加了用户,他们也没有被授予 CONNECT 权限,并且该用户或组进行的任何连接尝试都会产生用户登录错误。要解决此问题,您需要在 db 中为每个新用户/组执行以下操作:

USE [DatabaseName]
GO
GRANT CONNECT TO [Login/GroupName]
GO

回答by Mario Eis

This script generates GRANT statements for your roles. I like, that it supports column leven permissions. It has to be adapted to your need (ie. improve for more complex databases, concatenate statements and execute, include create statement for your role). But just to give you an idea:

此脚本为您的角色生成 GRANT 语句。我喜欢,它支持列级别权限。它必须适应您的需要(即改进更复杂的数据库、连接语句和执行、包括为您的角色创建语句)。但只是给你一个想法:

SELECT 'GRANT ' + database_permissions.permission_name + ' ON ' +
    CASE database_permissions.class_desc
        WHEN 'SCHEMA' THEN schema_name(major_id)
        WHEN 'OBJECT_OR_COLUMN' THEN
            CASE WHEN minor_id = 0 THEN object_name(major_id) COLLATE Latin1_General_CI_AS_KS_WS
            ELSE (SELECT object_name(object_id) + ' ('+ name + ')'
                  FROM sys.columns 
                  WHERE object_id = database_permissions.major_id 
                  AND column_id = database_permissions.minor_id) end
        ELSE 'other' 
    END + 
    ' TO ' + database_principals.name COLLATE Latin1_General_CI_AS_KS_WS
FROM sys.database_permissions
JOIN sys.database_principals
ON database_permissions.grantee_principal_id = database_principals.principal_id
LEFT JOIN sys.objects --left because it is possible that it is a schema
ON objects.object_id = database_permissions.major_id
WHERE database_permissions.major_id > 0
AND permission_name in ('SELECT','INSERT','UPDATE','DELETE')

回答by Andrew Savinykh

IN SSMS right clicking user/login/role node and selecting 'Script As' will script this particular user / login / role. You can't script role mebership this way though.

在 SSMS 中右键单击用户/登录名/角色节点并选择“脚本为”将编写此特定用户/登录名/角色的脚本。但是,您不能以这种方式编写角色成员身份。

Visual Studiowith 'Database Drvelopment' option and Red Gate SQL Comparecan generate the change script between to databases, this includes users, roles and role membership.

带有“Database Drvelopment”选项和Red Gate SQL Compare 的Visual Studio可以生成数据库之间的更改脚本,这包括用户、角色和角色成员资格。

Generated by VS role membership looks like this:

由 VS 角色成员生成如下所示:

EXECUTE sp_addrolemember @rolename = N'db_datareader', @membername = N'DOMAIN\User';

If you don't have VS, you can either write those manually, or create a sql script for generating them.

如果你没有 VS,你可以手动编写它们,或者创建一个 sql 脚本来生成它们。

I'm sure there also should be a free tool to do something like this, but since I don't need it as I have Visual Studio, I never looked for it.

我确信也应该有一个免费工具来做这样的事情,但由于我不需要它,因为我有 Visual Studio,所以我从未寻找过它。

Edit: I just realized that I'm answering a wrong question, you are asking about role permission and I'm telling you about role membership. Sorry about this. I'll leave this answer here in case it can be useful to someone else. Answer by Alex Aza looks good.

编辑:我刚刚意识到我回答了一个错误的问题,您是在询问角色权限,而我在告诉您角色成员资格。为此事道歉。我会在这里留下这个答案,以防它对其他人有用。Alex Aza 的回答看起来不错。

回答by Ben Thul

It's a pain, but everything you're looking for is in a couple of system views: sys.database_permissions, sys.database_principals, and sys.database_role_members. The reason it isn't a treat is because the major_id and minor_id in sys.database_permissions have different meanings based on the class column. But if your permissions are relatively simple, then this might not be so bad. Give it a look and see what you can get.

这很痛苦,但您正在寻找的一切都在几个系统视图中:sys.database_permissions、sys.database_principals 和 sys.database_role_members。它不是一种享受的原因是因为 sys.database_permissions 中的 major_id 和 minor_id 基于类列具有不同的含义。但如果您的权限相对简单,那么这可能还不错。看看它,看看你能得到什么。

回答by MudassiR ShaikH

-- Use this if you have a lot of permissions assigned to a Database Role
-- Before running, set results to Text

SET NOCOUNT ON

Use MyDB;  -- CHANGE DATABASE NAME

DECLARE @RoleName varchar(50) = 'sp_exec' --- change role name here

SELECT 'CREATE ROLE [' + @RoleName + '];'+ char(13)

SELECT  'GRANT ' + prm.permission_name + ' ON [' + 
OBJECT_NAME(major_id) + '] TO [' + rol.name + '] ;' + char(13) COLLATE Latin1_General_CI_AS

from sys.database_permissions prm

    join sys.database_principals rol on

        prm.grantee_principal_id = rol.principal_id

where rol.name = @RoleName

回答by Tim Debisz

I added a additional script feature to the code above. The select scripts out the role and permissions so you just need to execute the result:

我在上面的代码中添加了一个额外的脚本功能。选择脚本输出角色和权限,因此您只需要执行结果:

-- Update the RoleName with the name of your role
DECLARE @RoleName VARCHAR(75) = 'RoleName'

DECLARE @RoleTable TABLE ([GrantedBy] VARCHAR (50) NOT NULL, [Permission] VARCHAR (50) NOT NULL, [State] VARCHAR (50) NOT NULL)
DECLARE @RoleScript VARCHAR(75)

INSERT INTO @RoleTable SELECT p2.[name], dbp.[permission_name], dbp.[state_desc] 
FROM [sys].[database_permissions] dbp LEFT JOIN [sys].[objects] so
    ON dbp.[major_id] = so.[object_id] LEFT JOIN [sys].[database_principals] p
    ON dbp.[grantee_principal_id] = p.[principal_id] LEFT JOIN [sys].[database_principals] p2
    ON dbp.[grantor_principal_id] = p2.[principal_id]
WHERE p.[name] = @RoleName

SELECT 'USE [' +  DB_NAME() + '] CREATE ROLE [' + @RoleName + ']' AS 'Create Role'
SELECT 'USE [' +  DB_NAME() + '] GRANT ' + [Permission] + ' ON SCHEMA::[' + [GrantedBy] + '] TO [' + @RoleName + ']' AS 'Add Permissions' 
FROM @RoleTable