Nested loop through databases in loop - sql

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.

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.

How to handle a stored procedure with Input and Output parameter in a cursor?

I have a stored procedure that holds a query giving me a value as varchar (output) for an employee id (input).
My cursor holds a list of employee id and I want to loop the stored procedure and print the values for each employee id.
That is what I have tried so far:
DECLARE #MyCursor as CURSOR
DECLARE #InputPar as int
DECLARE #OutputPar as varchar(30)
SET #MyCursor = CURSOR FOR <query>
Open #MyCursor;
FETCH NEXT FROM #MyCursor INTO #InputPar
BEGIN
WHILE ##FETCH_STATUS = 0
Exec dbo.mySP #InputPar, #OutputPar Output
Print #OutputPar
FETCH NEXT FROM #MyCursor INTO #InputPar
END
CLOSE #MyCursor;
DEALLOCATE #MyCursor;
The error I get at the moment is Must declare the scalar variable "#QutputPar". The variable is declared above so I do not see where the problem is. Could anyone help me get my code running?
DECLARE #InputPar as int
DECLARE #OutputPar as varchar(30)
declare MyCursor cursor for <your query here>
Open MyCursor;
FETCH NEXT FROM MyCursor INTO #InputPar
Exec dbo.mySP #InputPar, #OutputPar Output
Print #OutputPar
CLOSE MyCursor;
DEALLOCATE MyCursor;
reason why you doing through cursor is not known,it can be replaced (99% of time) with a set based operation..Reason why you are not getting values is you are not reading output value correctly..
Below is the way to do
Declare #var int/varchar--delcare datatype as per u r need
Exec dbo.mySP #InputPar, #var Output
Print #var

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

Query that will apply to EVERY SQL Server database

I'm testing a drop database query for all databases that begin with a specific prefix. However, because that can easily lead to horrific things I'm taking my drop database query
declare #dbname nvarchar (200);
declare #query nvarchar (max);
DECLARE db_cursor CURSOR FOR
select name from sys.databases
where name like 'PREFIX%'
Open db_cursor
fetch next from db_cursor into #dbname
while ##FETCH_STATUS = 0
BEGIN
set #query = 'Drop Database ['+ #dbname + ']'
Exec(#query)
FETCH NEXT FROM db_cursor INTO #dbname
END
Close db_cursor
deallocate db_cursor
and want to change the Drop Database part to something that is less scary.
So MAIN QUESTION is there a simple SQL query that I could put in there that would always apply to any SQL Server database? So I know that this query will only affect the databases I want it to before switching it back to Drop Database?
EDIT: Better yet, a query that will return the names of the databases.
Like select name from sys.databases but one that will work with ['+ #dbname + '] to return only the names of databases with that prefix to ensure that this query affects the appropriate databases.
Instead of Exec(#query), just call PRINT #query. That will show you the SQL that you intend to run.
PRINT Documentation
First of all just execute the following query and it will tell you what databases will it bring forward in the rest of the code
select name from sys.databases
where name like 'PREFIX%'
Finally add a PRINT statement to see the final DROP DATABASE statements dynamically build inside the cursor.
Some minor improvement in your code:
declare #dbname SYSNAME;
declare #query nvarchar (max);
DECLARE db_cursor CURSOR LOCAL FORWARD_ONLY FOR
select name from sys.databases
where name like 'PREFIX%'
Open db_cursor
fetch next from db_cursor into #dbname
while (##FETCH_STATUS = 0)
BEGIN
set #query = 'Drop Database '+ QUOTENAME(#dbname)
--Exec sp_executesql #query --<-- For execution
-- PRINT #query --<-- For debugging
FETCH NEXT FROM db_cursor INTO #dbname
END
Close db_cursor
deallocate db_cursor

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.