Question :
Is it possible to get all database roles and server roles in the same query/script? if so then how can it be achieved?
Initially, I wrote two separate queries, one for server roles and another one for database roles I joined the two queries with ‘Union All’ but the issue is it doesn’t show any database Name which I need.
So I approached the problem from a new angle as the end goal is to get all the databases in the SQL server instance with the roles(e.g db_owner). This will be stored in a temp table from where I can export it to excel. So I wrote a script after doing some reading and online searching. In the following query, I am getting the database roles along with the respective database so that issue is resolved but I want server roles as well and I don’t know how to get those using this query. If anyone can help me to modify the script in a way that it provides both the server roles and the database roles along with server and database name.
DECLARE @DatabaseName SYSNAME,
@sql VARCHAR(1000)
DECLARE @ResultTable TABLE(DatabaseName VARCHAR(100), ServerName VARCHAR(100), Name VARCHAR(100), TypeDesc Varchar(100), DatabaseRole VARCHAR(100) )
DECLARE DatabaseCursor CURSOR
FOR SELECT Name FROM sys.databases
OPEN databaseCursor
FETCH NEXT FROM databaseCursor INTO @DatabaseName
WHILE (@@FETCH_STATUS = 0)
BEGIN
SET @sql ='SELECT ''' + @DatabaseName + ''' AS [Database],
''' +@@SERVERNAME + '''AS [Server Name],
logins.name Name,
logins.type_desc TypeDesc,
roles.name RoleName
FROM '+@databaseName+'.sys.database_role_members rm
INNER JOIN '+@databaseName +'.sys.database_principals roles ON rm.role_principal_id = roles.principal_id
INNER JOIN '+@databaseName+'.sys.database_principals logins ON rm.member_principal_id = logins.principal_id'
INSERT INTO @ResultTable EXEC(@sql)
FETCH NEXT FROM databaseCursor INTO @databaseName
END
CLOSE databaseCursor
DEALLOCATE databaseCursor
SELECT * FROM @ResultTable;
Answer :
Add an INSERT...SELECT
query to get the server-level role memberships. The example below also uses QUOTENAME
to properly handle the concatenated literals and identifiers.
DECLARE @DatabaseName SYSNAME,
@sql VARCHAR(1000);
DECLARE @ResultTable TABLE(DatabaseName VARCHAR(100), ServerName VARCHAR(100), Name VARCHAR(100), TypeDesc Varchar(100), DatabaseRole VARCHAR(100) );
DECLARE DatabaseCursor CURSOR
FOR SELECT Name FROM sys.databases;
OPEN databaseCursor;
FETCH NEXT FROM databaseCursor INTO @DatabaseName;
WHILE (@@FETCH_STATUS = 0)
BEGIN
SET @sql ='SELECT ' + QUOTENAME(@DatabaseName, '''') + ' AS [Database],
' + QUOTENAME(@@SERVERNAME,'''') + 'AS [Server Name],
logins.name Name,
logins.type_desc TypeDesc,
roles.name RoleName
FROM '+QUOTENAME(@databaseName) +'.sys.database_role_members rm
INNER JOIN '+QUOTENAME(@databaseName) +'.sys.database_principals roles ON rm.role_principal_id = roles.principal_id
INNER JOIN '+QUOTENAME(@databaseName) +'.sys.database_principals logins ON rm.member_principal_id = logins.principal_id';
INSERT INTO @ResultTable EXEC(@sql);
FETCH NEXT FROM databaseCursor INTO @databaseName;
END;
CLOSE databaseCursor;
DEALLOCATE databaseCursor;
--get server roles
INSERT INTO @ResultTable
SELECT
NULL
, @@SERVERNAME
, logins.name
, logins.type_desc
, roles.name AS RoleName
FROM master.sys.server_role_members AS rm
JOIN master.sys.server_principals AS roles ON rm.role_principal_id = roles.principal_id AND type_desc = N'SERVER_ROLE'
JOIN master.sys.server_principals AS logins ON rm.member_principal_id = logins.principal_id;
SELECT * FROM @ResultTable;