sp_change_users_login 'auto-fix', '<local_account>' - sql

How can I execute the sp_change_users_login so that it will auto-fix all local sql accounts?
in other words I can run the command to view all local accounts:
select * from sys.database_principals
where type = 's';
I now want those list of users to be used in the sp_change_users_login procedure.

You could use a cursor to get the list of names, and then loop through the cursor results. Within the loop you would do something like:
exec sp_change_users_login 'auto-fix', #nameVariable
You'd loop while ##FETCH_STATUS = 0. It returns non-zero when you have FETCHed all the rows from the cursor.
Here's more detail:
declare #userVar varchar(30)
declare users cursor for select name from sys.database_principals where type = 's';
open users
fetch next from users into #userVar
while ##FETCH_STATUS = 0
begin
exec sp_change_users_login 'auto_fix', #userVar
fetch next from users into #userVar
end
close users
deallocate users

Related

Cursor which create user and assign role

I have list of users which all will requer to be on server which used domain autentification, I have temp table in which Ian loading my users from cab file.
Than I need to create users based on records in my temp file
How to do cursor to create this records?
I was trying to do
DECLARE cursor1 CURSOR
FOR
SELECT *
FROM #temp;
OPEN cursor1
FETCH NEXT
FROM cursor1
INTO #userprofile
WHILE ##fetch_status = 0
BEGIN
CREATE user #userprofile
FOR LOGIN #userprofile GO
EXEC sp_addrolemember 'role'
,#userprofile
FETCH NEXT
FROM cursor1
INTO #userprofile
END
CLOSE cursor1
DEALLOCATE cursor1
However it's throwing me an error
Msg 102 Incorrect syntax near #userprofile and msg 137 must declare the scalar variable #userprofile
You cannot use variables inline as object names with the calls to commands such as CREATE USER. You need to do something like this and use dynamic sql instead:
EDIT - You could also use sp_adduser instead of dynamic sql in this example. However, this stored procedure has been deprecated as of SQL Server 2012. Therefore, if you are using this version of above, stick with dynamic sql and the CREATE USER command.
Dynamic SQL if SQL2012 or greater
DECLARE #UserProfile VARCHAR(20)
DECLARE cursor1 CURSOR
FOR
SELECT
*
FROM #temp;
OPEN cursor1
FETCH NEXT FROM cursor1 INTO #UserProfile
WHILE ##Fetch_Status = 0
BEGIN
DECLARE #Sql VARCHAR(MAX)
SET #Sql = 'Create user ' + #UserProfile + ' for login ' + #UserProfile
--PRINT #SQL
EXEC (#Sql)
EXEC sp_addrolemember 'role'
,#UserProfile
FETCH NEXT FROM cursor1 INTO #UserProfile
END
CLOSE cursor1
DEALLOCATE cursor1
sp_adduser if prior:
EXEC sys.sp_adduser #LogInAme = #UserProfile
,#Name_In_Db = #UserProfile
I have commented out the PRINT statement. However, if you uncomment it. You can see the commands it's creating from the cursor.

If given a list of SQL Server objects, how can I determine which databases each object resides in?

I have a list of over 200 databases objects. All of these are either tables, stored procedures and views.
All of these objects exist on a specific SQL Server, but I was not given a field specifying which database each object belong in.
Given a list of DB objects that exists somewhere on a specific server, how can I query the server to provide the containing database name for each object?
I had a similar issue, this is what worked for me:
-- List of objects .. store in a table somewhere with
-- a db column set to an empty string
create table tempdb.dbo._mylist ( name nvarchar(500), db nvarchar(500) )
insert tempdb.dbo._mylist values ('obj 1', '')
insert tempdb.dbo._mylist values ('obj 2', '')
-- Setup cursor for databases
DECLARE db_cursor CURSOR FOR
SELECT name from sys.databases WHERE [state] != 6 -- OFFLINE
-- Loop through cursor
OPEN db_cursor;
DECLARE #dbname sysname;
FETCH NEXT FROM db_cursor INTO #dbname;
WHILE (##FETCH_STATUS <> -1)
BEGIN;
-- added dbname to object list if found (joined using common collation)
EXECUTE ('use ' + #dbname + '; update l set db = db + '';' + #dbname + ''' from tempdb.dbo._mylist l join sysobjects o on o.name = l.name COLLATE SQL_Latin1_General_CP1_CI_AS;');
FETCH NEXT FROM db_cursor INTO #dbname;
END;
CLOSE db_cursor;
DEALLOCATE db_cursor;
GO
-- Select results
select name, db = isnull(stuff(db,1,1,''), '') from tempdb.dbo._mylist
-- Cleanup
drop table tempdb.dbo._mylist
You can write a script using the SP_MSFOREACHDB stored procedure to do this. You can find examples of this here This basically allows you to run a script against all the databases.
For Example, the statement below will allow you to search for a table name, and it will also return the associated databasename.
EXEC sp_Msforeachdb "USE [?]; SELECT '[?]' databaseName, * FROM sys.tables WHERE name = 'table_name'"

How to check if cursor exists (open status)

How do I check if a cursor is open or not? Because many times I am encountering the error 'Cursor already exists'. Please let me know how can I check whether a cursor is already in open status.
In fact I have closed as well as Deallocated it at the end (CLOSE ppm_cursor; DEALLOCATE ppm_cursor;) But Still i am getting the same error what could be the reason.
You can use the CURSOR_STATUS function to determine its state.
IF CURSOR_STATUS('global','myCursor')>=-1
BEGIN
DEALLOCATE myCursor
END
Close the cursor, if it is empty then deallocate it:
IF CURSOR_STATUS('global','myCursor') >= -1
BEGIN
IF CURSOR_STATUS('global','myCursor') > -1
BEGIN
CLOSE myCursor
END
DEALLOCATE myCursor
END
Just Small change to what Gary W mentioned, adding 'SELECT':
IF (SELECT CURSOR_STATUS('global','myCursor')) >= -1
BEGIN
DEALLOCATE myCursor
END
http://social.msdn.microsoft.com/Forums/en/sqlgetstarted/thread/eb268010-75fd-4c04-9fe8-0bc33ccf9357
I rarely employ cursors, but I just discovered one other item that can bite you here, the scope of the cursor name.
If the database CURSOR_DEFAULT is global, you will get the "cursor already exists" error if you declare a cursor in a stored procedure with a particular name (eg "cur"), and while that cursor is open you call another stored procedure which declares and opens a cursor with the same name (eg "cur"). The error will occur in the nested stored procedure when it attempts to open "cur".
Run this bit of sql to see your CURSOR_DEFAULT:
select is_local_cursor_default from sys.databases where name = '[your database name]'
If this value is "0" then how you name your nested cursor matters!
This happened to me when a stored procedure running in SSMS encountered an error during the loop, while the cursor was in use to iterate over records and before the it was closed. To fix it I added extra code in the CATCH block to close the cursor if it is still open (using CURSOR_STATUS as other answers here suggest).
Expanding on a previous answer, this proc is useful to call if you are worried that the cursor may have been left open or allocated
CREATE OR ALTER PROCEDURE dbo.CloseAndDeallocateCursor
#cursorName NVARCHAR(80)
AS
BEGIN
IF CURSOR_STATUS('global', #cursorName) >= -1
BEGIN
DECLARE #SQL NVARCHAR(91)
IF CURSOR_STATUS('global', #cursorName) > -1
BEGIN
SET #SQL = N'CLOSE ' + #cursorName
EXEC sp_executeSQL #SQL
END
SET #SQL = N'DEALLOCATE ' + #cursorName
EXEC sp_executeSQL #SQL
END
END
GO
... and then sample usage ...
EXEC dbo.CloseAndDeallocateCursor 'myCursor'
DECLARE myCursor STATIC
FOR SELECT * FROM blah

How to rename users, add a role etc, using script in t-sql

I have to
Rename users (from yyyyyy\xxxx to xxxx)
Add a role to the users
See the priviliges of stored procedures granted to a specified role (I found a table with the information regarding tables, but not stored procedure)
All in t-sql. I know how to do it mannualy, but with 400+ users, I hope to script me out of the problems.
Can anyone help?
What you need to do is loop over the users to modify and execute the commands to make the changes you need. You can do this by querying the syslogins table and creating a cursor with the results.
I have added the statement to rename the user, but adding the role is as simple as adding in a second statement and exec with sp_addrolemember
DECLARE #Login as varchar(50);
DECLARE LoginsCrsr CURSOR FOR
SELECT name
FROM syslogins
WHERE name like '%John%'; --Whatever critera you need
OPEN LoginsCrsr;
FETCH NEXT FROM LoginsCrsr
INTO #Login;
WHILE (##FETCH_STATUS = 0)
BEGIN
DECLARE #TSQL as varchar(255)
DECLARE #NewLogin as varchar(50)
SELECT #NewLogin = #Login -- Do your own thing here
SELECT #TSQL = 'ALTER LOGIN [' + #Login + '] WITH NAME=[' + #NewLogin + ']'
PRINT #TSQL
EXEC (#TSQL)
--Whatever else you need to do
FETCH NEXT FROM LoginsCrsr
INTO #Login
END
GO
CLOSE LoginsCrsr;
DEALLOCATE LoginsCrsr;
GO

Grant SELECT, UPDATE, INSERT, DELETE to all tables except 1 (or more) in SQL Server 2005

The user I have should have access to all tables in a database - SELECT, INSERT, UPDATE, DELETE and EXECUTE (ASP code to blame :-P) except for 1 table e.g. users.
When granting db_datareader and db_datawriter this gives them full access to everything and removing the DELETE permission on the users table will not work.
There are over 60 tables and was looking for a quicker way than using SSMS to go through every table and do this.
How would I go about doing this?
You can explicitly deny permissions which should take precedence. The syntax is
deny delete on dbo.users to username
You can use a hacky cursor and sp_executeSQL (GRANT can't take a variable tablename)
declare ctable cursor for
select Name from sysobjects where type = 'u'
declare #Name sysname
declare #ExecSQL nvarchar(512)
open ctable
fetch next FROM ctable into #Name
while (##FETCH_STATUS = 0)
begin
if (#Name <> 'MyTableToExclude')
BEGIN
SET #ExecSQL = 'grant SELECT on ' + #Name + ' to PUBLIC'
EXEC sp_executesql #ExecSQL
... etc
END
fetch next FROM ctable into #Name
end
close ctable
deallocate ctable
Minor ... note that you can't grant exec on tables ;)