Cursor which create user and assign role - sql

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.

Related

Issue executing Dynamic sql query

I have a SQL set of instructions that I want to execute across multiple databases. I currently have the following SQL code:
USE Database1
DECLARE #mySourceTable AS [someUserDefinedType];
/*Execute set of operations on Database 1 and #mySourceTable*/
DECLARE #dbList TABLE (DBName nvarchar(50));
INSERT INTO #dbList (DBName)
VALUES('Database2'),('Database3');
DECLARE #dbName nvarchar(50);
DECLARE dbCursor CURSOR FOR SELECT DBName FROM #dbList;
OPEN dbCursor;
FETCH NEXT FROM dbCursor INTO #dbName;
WHILE ##FETCH_STATUS = 0
BEGIN
EXECUTE('USE ' + #dbName + N';
DECLARE #content AS [someUserDefinedType];
INSERT INTO #content (ID)
SELECT ID FROM '+ #mySourceTable + N';
EXECUTE dbo.someProcedure #content;');
FETCH NEXT FROM dbCursor INTO #dbName;
END;
CLOSE dbCursor;
DEALLOCATE dbCursor;
Basically I want to do the following: I have several databases that all have the same [someUserDefinedType] table type (with the same structure) and a procedure named dbo.someProcedure that receives as a parameter a table of said type (the dbo.someProcedure is not the same across databases, it is specific to each). I want to go through the list of provided databases (#dbList) and execute each stored procedure with data from #mySourceTable. I am not sure if the code above is the best approach, it does not work and gives the error:
Must declare the scalar variable "#mySourceTable".
This variable is already declared at the beginning of the script. What am I doing wrong? Is it possible to pass the data from #mySourceTable using a variable and not create another table for it (I really want to avoid that)?
Try something like this:
USE Database1
DECLARE #mySourceTable AS [someUserDefinedType];
/*Execute set of operations on Database 1 and #mySourceTable*/
DECLARE #dbList TABLE (DBName nvarchar(50));
INSERT INTO #dbList (DBName)
VALUES('Database2'),('Database3');
DECLARE #dbName nvarchar(50);
DECLARE dbCursor CURSOR FOR SELECT DBName FROM #dbList;
OPEN dbCursor;
FETCH NEXT FROM dbCursor INTO #dbName;
DECLARE #DynamicTSQLStatement NVARCHAR(MAX);
WHILE ##FETCH_STATUS = 0
BEGIN
SET #DynamicTSQLStatement = N'
USE ' + #dbName + ';
DECLARE #content AS [someUserDefinedType];
INSERT INTO #content (ID)
SELECT ID FROM #mySourceTable;
EXECUTE dbo.someProcedure #content;';
FETCH NEXT FROM dbCursor INTO #dbName;
EXEC sp_executesql #DynamicTSQLStatement, N'#mySourceTable someUserDefinedType readonly', #mySourceTable = #mySourceTable
END;
CLOSE dbCursor;
DEALLOCATE dbCursor;
When you are executing T-SQL statement with sp_executesql you can pass parameters.

Nested loop through databases in loop

I have 4 the same databases
('User1','User2','User3','User4')
And a loop doing what it supposed to do:
DECLARE #json NVARCHAR(2000)
DECLARE #getid CURSOR
SET #getid = CURSOR FOR
SELECT [custom_data] FROM [User1].[usr].[table] where [custom_data] like '%:true%' or [custom_data] like '%:false%'
OPEN #getid
FETCH NEXT
FROM #getid INTO #json
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT JSON_MODIFY(#json, '$.field','value')
FETCH NEXT FROM #getid INTO #json
END
CLOSE #getid
DEALLOCATE #getid
My question is: How do I iterate through databases? I have tried to nest the loop containing variable with database name and then execute query in this way:
First I:
DECLARE C CURSOR FOR SELECT name FROM sysdatabases WHERE name IN ('User1','User2','User3','User4')
as described in many examples and after that I wanted to concat db name into query and execue it like that:
DECLARE #dbname varchar(50)
DECLARE C CURSOR FOR SELECT name FROM sysdatabases
WHERE name IN ('User1','User2','User3','User4')
OPEN C
WHILE ##FETCH_STATUS = 0
BEGIN
EXEC('DECLARE #json NVARCHAR(2000);
DECLARE #getid CURSOR; SET #getid = CURSOR FOR SELECT [custom_data] FROM '+#dbName+'.[usr].[transactions]
OPEN #getid;
FETCH NEXT;
FROM #getid INTO #json;
WHILE ##FETCH_STATUS = 0;
BEGIN;
SELECT JSON_MODIFY(#json, ''$.Field'',''Value'');
FETCH NEXT FROM #getid INTO #json
END
CLOSE #getid
DEALLOCATE #getid')
FETCH NEXT FROM C INTO #dbname
END
CLOSE C
DEALLOCATE C
but it finishes loop with no errors with massage
Commands completed successfully.
but it changes nothing. I would appreciate your assistance
Before you can execute a statement within the context of a specific database in ad-hoc sql your have to execute a USE statement like this (don't omit the GO instruction otherwise it won't work):
SET #sql = 'USE '+#dbname+';'+CHAR(13)+CHAR(10)+'GO'+CHAR(13)+CHAR(10)+'SELECT DB_NAME();'
Also, don't forget to use a FETCH NEXT FROM C INTO #dbname before your start your WHILE too otherwise your #dbname won't contain a usable value.

Cursor with Dynamic SQL Query

I'm trying to make a dynamic query, using a cursor, I wanna create filegroups to every tables on my database, I have this:
DECLARE #name VARCHAR(50)
DECLARE #query VARCHAR(50)
DECLARE vend_cursor CURSOR
FOR SELECT name FROM sys.tables order by name asc
OPEN vend_cursor
FETCH NEXT FROM vend_cursor;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT 'FG_'+#name
FETCH NEXT FROM vend_cursor INTO #name;
END
CLOSE vend_cursor
DEALLOCATE vend_cursor
The print is because then I can see how the filegroup name will be, but I wanna add this:
ALTER DATABASE AdventureWorks2012
ADD FILEGROUP FG_filegroupname
I know I have to use 'exec sys.sp_executesql', but how can I add this to my query? thanks in advance
Yes you can do this with sp_executeSQL but the most important thing is that you need to setup a GLOBAL cursor, because sp_executeSQL is not in the same scope as the procedure which you are executing. See example
DECLARE #SQL nvarchar(1024),
#name varchar(255);
SET #SQL = 'DECLARE vend_cursor CURSOR GLOBAL
FOR
SELECT name FROM sys.tables order by name asc';
EXECUTE sp_executesql #SQL;
OPEN vend_cursor
FETCH NEXT FROM vend_cursor INTO #name;
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT 'FG_'+#name
FETCH NEXT FROM vend_cursor INTO #name;
END
CLOSE vend_cursor
DEALLOCATE vend_cursor

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

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

Run script on multiple DBs (SQL Server)?

Let's say I have some update script:
update sometable set somecolumn = 'somevalue' where xyz = 0
Now let's say I have multiple databases, like DB1, DB2, DB3 and so on. How could I run this script on all of them without doing it manually?
Thanks :)
You can do this using cursor
get list of all server in your lan or in network
create cursor for that
Than make use of sp_executesql to run you update script with forpart query
set ANSI_NULLS ON
set QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [sp_cross_db_query]
#SQLQuery varchar(400)
AS
DECLARE #DB_Name varchar(100)
DECLARE database_cursor CURSOR FOR
SELECT DatabaseName
FROM Management.dbo.Customers
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
exec(
'USE [' + #DB_Name + '];' +
#SQLQuery
)
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
to run the query
exec sp_cross_db_query 'SELECT count(*) FROM Products'
If you wanted all databases, you can use sp_MSforeachdb:
http://www.databasejournal.com/features/mssql/article.php/3441031/SQL-Server-Undocumented-Stored-Procedures-spMSforeachtable-and-spMSforeachdb.htm
EXEC sp_MSforeachdb #command1="UPDATE ?..sometable SET somecolumn='somevalue' WHERE xyz=0"
Or for specific databases, you could try some of the logic as seen here:
http://www.sqlservercurry.com/2009/04/6-common-uses-of-undocumented-stored.html
Hope that helps.