October 8, 2004 at 3:31 pm
Comments posted to this topic are about the content posted at http://www.sqlservercentral.com/columni
1234
November 2, 2004 at 1:52 am
Elegant and simple in design, nice in execution. While the scripts themselves are useful, the written example of how to use a cursor was even more useful.
Now I can start re-writing that awful procedure I inherited from a now defunct developer to make it work like it should have done all along!
Thanks!
Ant Butler.
November 2, 2004 at 11:23 am
Thank you for this as I am working on the same issue right now.
November 2, 2004 at 11:37 am
Suggest adding:
SET @mSQL1 = 'TRUNCATE TABLE dbo.DBRoles'
EXECUTE (@mSql1)
After the initial DECLARE's to clear out the table if you run the Proc more than once. (Assumes you created the table under dbo). (Chose dynamic SQL in keeping with the style of the proc.)
Alternativey, you may want to include some "NOT EXISTS" logic to prevent adding duplicate role information, assuming the cur_date field enables you to track changes over time.
January 13, 2005 at 7:01 am
Here's a version that doesn't require the DBRoles table and executes the final SELECT with parameters so you can just execute List_DBRoles and specify things like "@dbo='Y' " or "@user='RS02130' " and get the results back immediately. It's pretty flexible.
CREATE procedure dbo.List_DBRoles
(
@database nvarchar(128)=null,
@user varchar(20)=null,
@dbo char(1)=null,
@access char(1)=null,
@security char(1)=null,
@ddl char(1)=null,
@datareader char(1)=null,
@datawriter char(1)=null,
@denyread char(1)=null,
@denywrite char(1)=null
)
as
declare @dbname varchar(200)
declare @mSql1 varchar(8000)
CREATE TABLE #DBROLES
( DBName sysname not null,
UserName sysname not null,
db_owner varchar(3) not null,
db_accessadmin varchar(3) not null,
db_securityadmin varchar(3) not null,
db_ddladmin varchar(3) not null,
db_datareader varchar(3) not null,
db_datawriter varchar(3) not null,
db_denydatareader varchar(3) not null,
db_denydatawriter varchar(3) not null,
Cur_Date datetime not null default getdate()
)
DECLARE DBName_Cursor CURSOR FOR
select name
from master.dbo.sysdatabases
where name not in ('mssecurity','tempdb')
Order by name
OPEN DBName_Cursor
FETCH NEXT FROM DBName_Cursor INTO @dbname
WHILE @@FETCH_STATUS = 0
BEGIN
Set @mSQL1 = ' Insert into #DBROLES ( DBName, UserName, db_owner, db_accessadmin,
db_securityadmin, db_ddladmin, db_datareader, db_datawriter,
db_denydatareader, db_denydatawriter )
SELECT '+''''+@dbName +''''+ ' as DBName ,UserName, '+char(13)+ '
Max(CASE RoleName WHEN ''db_owner'' THEN ''Yes'' ELSE ''No'' END) AS db_owner,
Max(CASE RoleName WHEN ''db_accessadmin '' THEN ''Yes'' ELSE ''No'' END) AS db_accessadmin ,
Max(CASE RoleName WHEN ''db_securityadmin'' THEN ''Yes'' ELSE ''No'' END) AS db_securityadmin,
Max(CASE RoleName WHEN ''db_ddladmin'' THEN ''Yes'' ELSE ''No'' END) AS db_ddladmin,
Max(CASE RoleName WHEN ''db_datareader'' THEN ''Yes'' ELSE ''No'' END) AS db_datareader,
Max(CASE RoleName WHEN ''db_datawriter'' THEN ''Yes'' ELSE ''No'' END) AS db_datawriter,
Max(CASE RoleName WHEN ''db_denydatareader'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatareader,
Max(CASE RoleName WHEN ''db_denydatawriter'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatawriter
from (
select b.name as USERName, c.name as RoleName
from ' + @dbName+'.dbo.sysmembers a '+char(13)+
' join '+ @dbName+'.dbo.sysusers b '+char(13)+
' on a.memberuid = b.uid join '+@dbName +'.dbo.sysusers c
on a.groupuid = c.uid )s
Group by USERName
order by UserName'
--Print @mSql1
Execute (@mSql1)
FETCH NEXT FROM DBName_Cursor INTO @dbname
END
CLOSE DBName_Cursor
DEALLOCATE DBName_Cursor
Select * from #DBRoles
where ((@database is null) OR (DBName LIKE '%'+@database+'%')) AND
((@user is null) OR (UserName LIKE '%'+@user+'%')) AND
((@dbo is null) OR (db_owner = 'Yes')) AND
((@access is null) OR (db_accessadmin = 'Yes')) AND
((@security is null) OR (db_securityadmin = 'Yes')) AND
((@ddl is null) OR (db_ddladmin = 'Yes')) AND
((@datareader is null) OR (db_datareader = 'Yes')) AND
((@datawriter is null) OR (db_datawriter = 'Yes')) AND
((@denyread is null) OR (db_denydatareader = 'Yes')) AND
((@denywrite is null) OR (db_denydatawriter = 'Yes'))
GO
January 13, 2005 at 7:02 am
...MS Supplies the following:
Exec sp_HelpLogins
Exec sp_HelpUser
Exec sp_HelProtect
Exec sp_HelpSrvRoleMember
Exec sp_HelpRoleMember
January 13, 2005 at 7:31 am
Based on some quick empirical testing the above SP's only apply to the current database. The new SP posted above lists all relevant data (OK, we could add SID if you really want it) for all databases on the server assuming you have appropriate access to dbo.sysmembers and dbo.sysusers. I believe in a standard SQL Server setup everyone has READ access to these tables so the SP consolidates a lot of information in one place. The MS SP's (it seems) have to be run in each DB separately and the information correlated.
January 13, 2005 at 8:50 am
> The MS SP's (it seems) have to be run in each DB separately and the information correlated.
Use Master
Go
Exec master..sp_HelpUser
Exec pubs..sp_HelpUser
Exec northwind..sp_HelpUser
January 13, 2005 at 9:02 am
Still, you have to run it against each DB as opposed to the posted SP which gets all the DB names from master.dbo.sysdatabases and recurses the list. OK, it uses a cursor. When I have some time maybe I'll see if I can convert it to set-based processing.
November 2, 2005 at 8:36 am
Great piece of work, I have meant to do this for quite awhile...
Two minor suggestions:
One, may want to use consistent casing in case you run this procedure in a "case sensitive" environment.
Secondly, may want to add a check to bypass any database that is temporarily offline:
and databaseproperty(name, 'IsOffline') = 0
Cheers!
November 2, 2005 at 2:53 pm
Interesting, though a bit long winded way to do it. Lots of good tips in this thread though.
John Scarborough
MCDBA, MCSA
February 3, 2009 at 6:16 pm
Superb!
Joining sysmembers and sysusers is a superb idea.
Just used it in a recovery from crash.
Thank you
March 11, 2010 at 1:51 pm
Great stuff. This has been here a while bit if anyone is interested. Similiar code.
Slightly modified to work with SQLOverview. With it I can hit several servers. Now I get the data I am looking for a way to determine any changes. I have some ideas to determine changes or additions to any database/user/roles. Anyone done anything like this with out a trigger?
IF EXISTS
(SELECT *
FROM tempdb.dbo.sysobjects
WHERE id = OBJECT_ID(N'[tempdb].[dbo].[DBROLES]')
)
DROP TABLE [tempdb].[dbo].[DBROLES]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE [tempdb].[dbo].[DBROLES](
[ServerName] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL CONSTRAINT [DF_DBROLES_ServerName] DEFAULT (N'.'),
[DBName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[UserName] [sysname] COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_owner] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_accessadmin] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_securityadmin] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_ddladmin] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_datareader] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_datawriter] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_denydatareader] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[db_denydatawriter] [varchar](3) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[createdate] [datetime] NOT NULL,
[updatedate] [datetime] NOT NULL,
[Cur_Date] [datetime] NOT NULL CONSTRAINT [DF__DBROLES__Cur_Dat__3A179ED3] DEFAULT (getdate())
) ON [PRIMARY]
GO
INSERT INTO [tempdb].[dbo].[DBROLES]
EXEC sp_MSForEachDB
'SELECT CONVERT(nvarchar(128), SERVERPROPERTY(''Servername'')) AS ServerName,
''?'' as DBName,
UserName,
Max(CASE RoleName WHEN ''db_owner'' THEN ''Yes'' ELSE ''No'' END) AS db_owner,
Max(CASE RoleName WHEN ''db_accessadmin '' THEN ''Yes'' ELSE ''No'' END) AS db_accessadmin ,
Max(CASE RoleName WHEN ''db_securityadmin'' THEN ''Yes'' ELSE ''No'' END) AS db_securityadmin,
Max(CASE RoleName WHEN ''db_ddladmin'' THEN ''Yes'' ELSE ''No'' END) AS db_ddladmin,
Max(CASE RoleName WHEN ''db_datareader'' THEN ''Yes'' ELSE ''No'' END) AS db_datareader,
Max(CASE RoleName WHEN ''db_datawriter'' THEN ''Yes'' ELSE ''No'' END) AS db_datawriter,
Max(CASE RoleName WHEN ''db_denydatareader'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatareader,
Max(CASE RoleName WHEN ''db_denydatawriter'' THEN ''Yes'' ELSE ''No'' END) AS db_denydatawriter,
createdate,
updatedate,
GETDATE()
from (
select b.name as USERName, c.name as RoleName, b.createdate, b.updatedate
from [?].dbo.sysmembers a
join [?].dbo.sysusers b on a.memberuid = b.uid
join [?].dbo.sysusers c
on a.groupuid = c.uid )s
Group by USERName, createdate, updatedate
order by UserName'
SET ANSI_PADDING OFF
May 4, 2010 at 2:19 am
After executing this I got a list of all users and their database access and roles. Then I realized something was missing. I used to login to sql server 2000 and execute sql statements. I am local system admin. I can see a login named Builtin\Administrator under security and this has access to all database as db_public and db_owner.
Here i have 2 questions
1. Why is Builtin\administrators not listed ? doest that mean that the procedure and query given in the link is wrong.
2. I can see certain users who has access to few of the databases. But these users are not in the login section under security. How can a user have access to database without a login ?
I would be extremely thankful to you could clarify my queries.
Thanks
August 17, 2010 at 3:41 pm
hi how would you run this for one login?
Viewing 15 posts - 1 through 15 (of 19 total)
You must be logged in to reply to this topic. Login to reply