SQL SERVER query cursor with dynamic LinkedServer - sql-server

I want to monitor few SQL SERVER instances (about 31), and I want to prepare a procedure that will aggregate data from instances based on sys.servers list, but I cant dynamically ask a server.
DECLARE #instance_name sysname;
DECLARE instance_cursor CURSOR FOR
select data_source from sys.servers where is_linked = 1;
OPEN instance_cursor
FETCH NEXT FROM instance_cursor INTO #instance_name
WHILE ##FETCH_STATUS = 0
BEGIN
--Do something on a linked server
SELECT 1 FROM #instance_name.master.sys.master_files
FETCH NEXT FROM instance_cursor INTO #instance_name
END
CLOSE instance_cursor
DEALLOCATE instance_cursor

USE master
GO
IF OBJECT_ID('tempdb..#server_info') IS NOT NULL
DROP TABLE #server_info
CREATE TABLE #server_info
(
Col1 SQL_VARIANT,
Col2 SQL_VARIANT,
Col3 SQL_VARIANT,
Col4 SQL_VARIANT
) -- change data type as needed.
DECLARE #instance_name NVARCHAR(255);
DECLARE #sql NVARCHAR(MAX)
DECLARE instance_cursor CURSOR FOR
SELECT name FROM master.sys.servers WHERE is_linked = 1
ORDER BY name
OPEN instance_cursor
FETCH NEXT FROM instance_cursor INTO #instance_name
WHILE ##FETCH_STATUS = 0
BEGIN
--Do something on a linked server
SET #sql = 'INSERT INTO #server_info (Col1,Col2,Col3,Col4) SELECT .... FROM ' + #instance_name + '.master.sys...'
PRINT #sql -- verify for your syntax
EXEC (#sql)
FETCH NEXT FROM instance_cursor INTO #instance_name
END
CLOSE instance_cursor
DEALLOCATE instance_cursor
SELECT * FROM #server_info

I'm not found a perfect solution for this, but:
CREATE PROCEDURE [kk].[query_ls]
#SQL NVARCHAR(MAX)
AS
BEGIN
DECLARE #query NVARCHAR(MAX);
DECLARE #instance_name sysname;
DECLARE instance_cursor CURSOR FOR
select data_source from sys.servers where is_linked = 1;
OPEN instance_cursor
FETCH NEXT FROM instance_cursor INTO #instance_name
WHILE ##FETCH_STATUS = 0
BEGIN
SET #query = REPLACE(#SQL,'#server#',#instance_name )
EXEC (#query)
FETCH NEXT FROM instance_cursor INTO #instance_name
END
CLOSE instance_cursor
DEALLOCATE instance_cursor
END
And usage example:
EXEC [kk].[query_ls] N'use _dba INSERT INTO kk.cpuUsagePerDB select *,getdate() from [#server#]._dba.kk.[V_cpuUsagePerDB]'
Another solution can be achieved by OPENQUERY

Related

how to use variable name as table name in update statement

I have a table(Lets say'A') that contains the list of all tables in a database.I have defined a cursor that iterate through the tables name in 'A'.I want to update the table column defined in a cursor.
I have created 2 cursors.One to iterate over the tables names and other one to iterate over the column names.
DECLARE #MyCursor CURSOR;
DECLARE #MyField nvarchar(255);
BEGIN
SET #MyCursor = CURSOR FOR
select distinct Table_name from DataTable where Data <>'No'
set #a=0
OPEN #MyCursor
FETCH NEXT FROM #MyCursor
INTO #MyField
WHILE ##FETCH_STATUS = 0
BEGIN
DECLARE #column_cursor CURSOR;
DECLARE #columnField nvarchar(255);
SET #column_cursor = CURSOR FOR
select Column_name from DataTable where TABLE_NAME=#MyField and Data
<>'No'
OPEN #column_cursor
FETCH NEXT FROM #column_cursor
INTO #columnField
WHILE ##FETCH_STATUS = 0
BEGIN
update #MyField set #columnField=''+#MyField+'_'+#columnField+#a
FETCH NEXT FROM #column_cursor
INTO #columnField
END;
CLOSE #column_cursor ;
DEALLOCATE #column_cursor;
FETCH NEXT FROM #MyCursor
INTO #MyField
END;
CLOSE #MyCursor ;
DEALLOCATE #MyCursor;
END;
Here in the update statement #MyField is giving error :"Must declare the table variable #MyField".
You are on good way but you can't use variable on table name place , you need to build your update command in variable and then execute dynamic sql.
You can see: Creating a dynamic sql query
in your case someting like
declare #sqlCommand varchar(max)
declare #MyField varchar(255) = 'table_name'
declare #columnField varchar(255) = 'column_NAME'
declare #columnValue varchar(255) = 'column_value'
set #sqlCommand = 'update '+ #MyField +' set '+#columnField+' = ' +#columnValue+ ' where 1=1;'
--select #sqlCommand
EXEC (#sqlCommand)

Cursorfetch: The number of variables declared in the INTO list must match that of selected columns in SQL Server 2012

I created a stored procedure that validates certain columns given a table as parameter and decided to use Cursor. But I am getting this cursor fetch error when trying to execute the stored procedure.
I already double checked the columns and it matches the number of variables in INTO list. I tried modifying the stored procedure by writing this
SELECT Lot, ItemId, PO, Status, ErrorDetails
FROM Table1
instead of
SELECT #SQLSTATEMENT
after
SET #MyCursor = CURSOR FOR
and it works fine. But I want the source table to be a parameter so this won't work for me. Any ideas?
CREATE PROCEDURE [dbo].[ValidateData]
#TABLENAME_PARAM NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
DECLARE #MyCursor CURSOR;
DECLARE #CustomerLot NVARCHAR(100),
#DeviceName NVARCHAR(100),
#PO NVARCHAR(100),
#Status NVARCHAR(1),
#ErrorDetails NVARCHAR(250);
DECLARE #TABLENAME NVARCHAR(100);
DECLARE #SQLSTATEMENT AS NVARCHAR(MAX);
SELECT #TABLENAME = Quotename (TABLE_NAME)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #TABLENAME_PARAM
SET #SQLSTATEMENT = 'Select Lot, ItemId, PO, Status, ErrorDetails FROM ' + #TABLENAME + ' WHERE Status = ''N'''
BEGIN
SET #MyCursor = CURSOR FOR
SELECT #SQLSTATEMENT
OPEN #MyCursor
FETCH NEXT FROM #MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRAN
--some validations here
COMMIT TRAN
FETCH NEXT FROM #MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
END;
CLOSE #MyCursor;
DEALLOCATE #MyCursor;
END
END
GO
Try this-
CREATE PROCEDURE [dbo].[ValidateData] #TABLENAME_PARAM NVARCHAR(100)
AS
BEGIN
SET NOCOUNT ON;
--DECLARE #MyCursor CURSOR;
DECLARE
#CustomerLot NVARCHAR(100),
#DeviceName NVARCHAR(100),
#PO NVARCHAR(100),
#Status NVARCHAR(1),
#ErrorDetails NVARCHAR(250);
DECLARE #TABLENAME NVARCHAR(100);
DECLARE #SQLSTATEMENT AS NVARCHAR(MAX);
SELECT #TABLENAME = Quotename (TABLE_NAME)
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_NAME = #TABLENAME_PARAM
SET #SQLSTATEMENT = 'DECLARE MyCursor CURSOR FOR Select Lot, ItemId, PO, Status, ErrorDetails FROM ' + #TABLENAME + ' WHERE Status = ''N'''
EXEC sp_executesql #sqlstatement
OPEN MyCursor
FETCH NEXT FROM MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
WHILE ##FETCH_STATUS = 0
BEGIN
BEGIN TRAN
--some validations here
COMMIT TRAN
FETCH NEXT FROM MyCursor INTO #CustomerLot, #DeviceName, #PO, #Status, #ErrorDetails
END;
CLOSE MyCursor;
DEALLOCATE MyCursor
END
END
GO

Transact sql : must declare the scalar variable

I'm trying to iterate over some tables and clear all records.
My code is the following :
DECLARE #table varchar(100)
DECLARE db_cursor CURSOR FOR select name from sys.tables where name like '%cfe_%'
OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO #table
WHILE ##FETCH_STATUS = 0  
BEGIN  
print #table
delete from #table
       FETCH NEXT FROM db_cursor INTO #table  
END  
CLOSE db_cursor  
DEALLOCATE db_cursor
But I receive "Must declare the table variable "#table" at the line "delete..."
I can't see the error.
Thank you
You shoud use dynamic query,
DECLARE #table varchar(100)
,#v_str nvarchar(200)
DECLARE db_cursor CURSOR FOR select name from sys.tables where name like '%cfe_%'
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
print #table
set #v_str = 'delete from '+#table
exec(#v_str)
FETCH NEXT FROM db_cursor INTO #table
END
CLOSE db_cursor
DEALLOCATE db_cursor
You need dynamic delete statement... Try this :
DECLARE #cmd VARCHAR(4000)
DECLARE #table varchar(100)
DECLARE db_cursor CURSOR FOR select name from sys.tables where name like '%cfe_%'
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO #table
WHILE ##FETCH_STATUS = 0
BEGIN
SET #cmd = 'DELETE FROM '+#table
EXEC (#cmd)
FETCH NEXT FROM db_cursor INTO #table
END
CLOSE db_cursor
DEALLOCATE db_cursor
Even better would be to not use a cursor here. Looping in sql is a last resort. Also, your query is not going to do exactly what you think it will because you are using like and wanting to find an underscore. The underscore in a LIKE predicate requires it to be escaped with square brackets. As posted your query will return any table with cfe in the name not cfe_.
Once you are comfortable that the dynamic sql string is what you want you can uncomment it to execute it.
declare #SQL nvarchar(max) = ''
select #SQL = #SQL + 'delete from ' + name + ';'
from sys.tables
where name like '%cfe[_]%'
select #SQL
--exec sp_executesql #SQL
We can also use while loop for this process
DECLARE #Min Int,#max Int
IF Object_id('Tempdb..#DeleteList')IS NOT NULL
DROP TABLE #DeleteList
CREATE TABLE #DeleteList (Id Int Identity,Name varchar(100))
INSERT INTO #DeleteList(Name)
SELECT name FROM sys.tables WHERE CHARINDEX('cfe_',name)>0
SELECT #Min=Min(Id) FROm #DeleteList
SELECT #max=MAX(Id) FROm #DeleteList
While(#Min<=#max)
Begin
Declare #TableName Varchar(50),
#Sql Nvarchar(max)
SELECT #TableName=Name From #DeleteList Where id=#Min
SET #Sql='DELETE From '+#TableName
Exec (#Sql)
SET #Min=#Min+1
END
But if the deleting tables have foreign key refrences it will throw error so that first you need delete records from child and then go to Parent table
You will need to do something like;
EXEC sp_executesql #statement = N'DELETE FROM ' + #table
because currently you are trying to delete from a String variable, not the table named the same as the variable

sql cursor insert result into a table

I have created a cursor which iterates through all the databases and displays the 1 record per database.
I would like the records to be inserted into 1 table where I can view it. The query may change which is why I don't want to create the table structure for a specific query and insert it. I wanted to use the "select into" clause but that will fail on the second time the cursor runs
DECLARE #DB_Name varchar(100)
DECLARE #Command nvarchar(200)
DECLARE database_cursor CURSOR FOR SELECT name FROM #DBNAME
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'use [' + #DB_Name + '] Select '''+ #DB_Name + ''' ,'+
--Enter query below
'* from authentication where username like ''%clair#indicater%'' and password = ''Rohan2410'''
-- print #Command
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
You should better use INSERT INTO ... instead of SELECT INTO, something like this:
DECLARE #DB_Name varchar(100)
DECLARE #Command nvarchar(200)
DECLARE database_cursor CURSOR FOR SELECT name FROM #DBNAME
OPEN database_cursor
FETCH NEXT FROM database_cursor INTO #DB_Name
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #Command = 'use [' + #DB_Name + ']
IF OBJECT_ID(''tempdb..##output'') IS NULL
BEGIN
SELECT NULL AS DB_Name,*
INTO ##output
FROM authentication WHERE 1=0
END
INSERT INTO ##output
Select '''+ #DB_Name + ''' ,'+
--Enter query below
'* from authentication where username like ''%clair#indicater%'' and password = ''Rohan2410'''
-- print #Command
EXEC sp_executesql #Command
FETCH NEXT FROM database_cursor INTO #DB_Name
END
CLOSE database_cursor
DEALLOCATE database_cursor
SELECT * FROM ##output
DROP TABLE ##output
Basically, on the first cursor iteration we will create an empty temp table with the correct structure. Then we just insert into that temp table.

T-SQL cursor for linked server INSERT SELECT

I'm trying to get this cursor loop to work, so I could copy data from linked server to another server. However it seems that the cursor is in a loop and does nothing. What am I doing wrong?
/* For testing purposes I'm fetching data from
1 company only. The result should be one row.*/
DECLARE #tmp_key VARCHAR(14)
DECLARE #db cursor
DECLARE #sql NVARCHAR(MAX)
SET #db = CURSOR FOR
SELECT [CompanyId] FROM [Test].[dbo].[Company] WHERE [CompanyId] = '0001'
SET #sql = N'INSERT INTO [Stagingarea].[dbo].[Cominfo]
SELECT
convert(nvarchar(100),[Nro])
,convert(nvarchar(100),'+#tmp_key+' )
FROM [Linked_server_name].TK'+#tmp_key+'.[dbo].[cominfo]
where [rule1] <> 0 and acc = 1777';
OPEN #db
FETCH NEXT FROM #db INTO #tmp_key
while (##fetch_status = 0)
begin
EXEC sp_sqlexec #sql
end;
CLOSE #db
DEALLOCATE #db
You should put the dynamic SQL inside the WHILE loop. Make sure to call FETCH NEXT inside to avoid infinite loop.
DECLARE #tmp_key VARCHAR(14)
DECLARE #db cursor
DECLARE #sql NVARCHAR(MAX)
SET #db = CURSOR FOR
SELECT [CompanyId] FROM [Test].[dbo].[Company] WHERE [CompanyId] = '0001'
OPEN #db
FETCH NEXT FROM #db INTO #tmp_key
WHILE(##FETCH_STATUS = 0) BEGIN
SET #sql = N'INSERT INTO [Stagingarea].[dbo].[Cominfo]
SELECT
CONVERT(NVARCHAR(100), [Nro])
,CONVERT(NVARCHAR(100),' + #tmp_key +')
FROM [Linked_server_name].TK' + #tmp_key + '.[dbo].[cominfo]
WHERE [rule1] <> 0 AND acc = 1777';
EXEC sp_sqlexec #sql
FETCH NEXT FROM #db INTO #tmp_key
END;
CLOSE #db
DEALLOCATE #db

Resources