December 12, 2013 at 5:15 am
Hi there - I am trying to use a nested cursor to execute a script against all usernames across all database. I have a cursor for Username and Database but I can't get my code to cursor through the Databases cursor. Can someone help me to find a solution to this problem;
-------------------------------------------------------
------------------------------------------------------
DECLARE @DATABASE VARCHAR (70)
DROP TABLE #DATABASELOV
CREATE TABLE #DATABASELOV (DATABASENAME VARCHAR (70))
INSERT INTO #DATABASELOV (DATABASENAME) SELECT NAME FROM SYS.DATABASES where name not in ('master','tempdb','model','msdb')
DECLARE DATABASENAMEC CURSOR
FOR
SELECT DATABASENAME
FROM #DATABASELOV
OPEN DATABASENAMEC
FETCH NEXT FROM DATABASENAMEC INTO @DATABASE
WHILE @@FETCH_STATUS = 0
BEGIN
declare @sql2 varchar (255)
DROP TABLE #orphaneduseraccounts
set @sql2 = 'exec sp_change_users_login ''Report'''
CREATE TABLE #orphaneduseraccounts
(
Username VARCHAR(255) ,
UserSID VARCHAR(255)
)
INSERT INTO #orphaneduseraccounts
( Username, UserSID )
exec ( 'USE' + ' ' + @DATABASE + ' ' + @sql2 )
DECLARE @Username VARCHAR(255)
DECLARE @sql VARCHAR(MAX)
DECLARE UsernameCursor CURSOR
FOR
SELECT Username
FROM #orphaneduseraccounts
OPEN UsernameCursor
FETCH NEXT FROM UsernameCursor INTO @Username
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = 'EXEC sp_change_users_login ''Auto_Fix'','''
exec ( 'USE' + ' ' + @DATABASE + ' ' + @sql + @Username + '''' )
FETCH NEXT FROM UsernameCursor INTO @Username
END
CLOSE DATABASENAMEC
DEALLOCATE DATABASENAMEC
end
CLOSE UsernameCursor
DEALLOCATE UsernameCursor
---------------------------------------
---------------------------------------
Thanks, Russell
--------------------------------------------
Laughing in the face of contention...
December 12, 2013 at 6:11 am
Rather than look at your code, I've supplied a script I use that does the the same thing (fix orphaned users across all databases).
Mine uses UPDATE_ONE, but you could change it to use AUTO_FIX if you prefer.
exec sp_msforeachdb 'use [?];
declare @sql varchar(max)
select @sql = s from (
select ''use ['' + db_name() + '']; exec sp_change_users_login ''''Update_One'''', '''''' + d.name + '''''', '''''' + d.name + '''''';''
from sys.database_principals d
join sys.server_principals p on d.name = p.name collate database_default
left join sys.server_principals o on d.sid = o.sid
where o.name is null
and d.name not in (''public'')
for xml path('''')) x(s);
if @sql is not null exec(@sql)
'
December 12, 2013 at 7:27 am
You are closing your cursors in the wrong order. You need to close the UsernameCursor within the outer while loop (DATABASENAMEC).
Interesting side note, I've never had to fix orphan users on all of the databases on a SQL instance, only a single database. I can see the need to do this if you are moving all of the databases from one server to another, which is what I'm guessing you are doing.
I have a script that I use to fix orphans that I put in a database called DBA, which has all of my utilities. Here is mine:
USE [DBA]
GO
/****** Object: StoredProcedure [dbo].[FixOrphanUsers] Script Date: 12/12/2013 09:26:40 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
Purpose : This procedure fixes orphan users. Simply pass in the Database and all users will be fixed.
Orphan users are created by moving databases from one server to another and SQL Server login users are carried
along. They will have different internal identities. This procedure will resync those users.
This procedure is based on the following call:
EXEC sp_change_users_login 'Auto_Fix', 'user'
Author : KWZimmerman - Lefrak Organization
Date : 11/18/2013
Requirements: None
Updates Date By Comment
------- ---------- --- ---------------
11/18/2013 KWZ Initial release
*/
ALTER procedure [dbo].[FixOrphanUsers] (
@Database varchar(max) = null
)
as
if @Database is null
begin
print 'Missing database name!'
print 'Call : ex ' + OBJECT_NAME(@@PROCID) + ' @Database = ''<database name>'''
end
else
begin
declare @ExcludeUser table (ID int primary key identity (1,1)
,User_Name varchar(50)
)
declare @User_Name varchar(50)
declare @sql varchar(max)
declare @CRLF char(2) = char(13) + char(10)
insert into @ExcludeUser (User_Name) values ('public')
insert into @ExcludeUser (User_Name) values ('dbo')
insert into @ExcludeUser (User_Name) values ('guest')
declare @Users table (ID int primary key identity (1,1)
,User_Name varchar(100)
)
select @sql = 'use ' + @Database + '; select distinct USER_NAME(sdp.grantee_principal_id) as User_Name' + @CRLF
select @sql += 'from sys.database_permissions sdp;' + @CRLF
insert into @Users
exec (@SQL)
delete from @Users
from @Users u left join
@ExcludeUser EU on u.User_Name = eu.User_Name
where eu.ID is not null
declare FixUser_Cursor cursor for
select distinct User_Name
from @Users
open FixUser_Cursor
fetch next from FixUser_Cursor into @User_Name
while @@FETCH_STATUS = 0
begin
set @sql = 'use ' + @Database + '; exec sp_change_users_login ''Auto_Fix'',''' + @User_Name + ''''
print @sql
exec (@SQL)
fetch next from FixUser_Cursor into @User_Name
end
close FixUser_Cursor
deallocate FixUser_Cursor
end
Kurt
Kurt W. Zimmerman
SR DBA
Lefrak Organization
New York, NY
http://www.linkedin.com/in/kurtwzimmerman
December 12, 2013 at 8:34 am
Thanks Chaps.
Yes, Kurt. This is to manage multiple databases, where majority of the time I don't know what the database names are that are being restored. As the db's are in a test environment I've take the all or nothing approach to my code.
Thanks for SP Richard. I wasn't aware this existed. I have decided to use it as its a much cleaner approach to what i'm trying to achieve.
Thanks, Russell.
--------------------------------------------
Laughing in the face of contention...
December 12, 2013 at 11:08 am
While the order of closing is wrong, I might also point out that you aren't FETCHING the next DB inside of the loop, so you're pulling one DB, cycling through the users and then closing the DB cursor.
If you flipped the order of the cursors being closed AND fetched the next DB, your code would work I thinnk.
----------------------------------------------------------------------------------
Your lack of planning does not constitute an emergency on my part...unless you're my manager...or a director and above...or a really loud-spoken end-user..All right - what was my emergency again?
Viewing 5 posts - 1 through 4 (of 4 total)
You must be logged in to reply to this topic. Login to reply