Pass Variable in SELECT FROM Loop - sql-server

I'm looking to select from multiple tables (MainTbl) but it will be based on the result set (StateTbl) of which tables would be pulled.
MainTables dbo.TABLE_MO, dbo.TABLE_CA, dbo.TABLE_AL, dbo.TABLE_MI
Only looking to pull based on resultset StateTbl MO, CA, WA
Declare #Loop_Count int = 0
DECLARE #State varchar(2)
DECLARE #SQL varchar(max)
DECLARE db_cursor CURSOR FOR SELECT State FROM StateTbl
OPEN db_cursor
FETCH db_cursor INTO #State
WHILE (##FETCH_STATUS = 0)
BEGIN
SET #SQL =
'
dbo.TABLE_'+ #State +'
'
EXEC(#SQL)
SET #Loop_Count = #Loop_Count + 1
FETCH db_cursor INTO #SQL
END
CLOSE db_cursor
DEALLOCATE db_cursor

Instead of a loop you can leverage dynamic and the StateTbl to build your dynamic sql. Something like this.
declare #SQL nvarchar(max) = ''
select 'select * from TABLE_' + [State] + ' UNION ALL '
from StateTbl
select #SQL = left(#SQL, len(#SQL) - 10)
select #SQL
--uncomment the line below when you satisfied the dynamic sql is written the way you want it.
--exec sp_executesql #SQL

Related

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

Replacing cursor with set based query

I want to find count of set of tables. The table names are values in another table.
--like
select count(*) from tablename
--tablename is obtained from
select tablename from table1
--table1 has around 171 tablenames
I was using cursor to get each table name and select count for each, but it is taking time. Can you please help how to replace cursor code with set based solution?
Below is my cursor code
SET NOCOUNT ON;
if( OBJECT_ID('tempdb..#temptablenew') IS NOT NULL )
BEGIN
DROP table #temptablenew
END
select * into #temptablenew from table1
declare #srccount int
declare #tablename nvarchar(max);
declare #q2 nvarchar(max);
declare #id int;
declare my_cursor cursor
local static read_only forward_only
for
select id,tablename from #temptablenew
open my_cursor
fetch next from my_cursor
into #id,#tablename
while ##fetch_status = 0
begin
set #q2 =N'select #srccount= count(*) from '+#tablename+' with (nolock)';
execute sp_executesql #q2,#PARAMS = N'#srccount INT OUTPUT',
#srccount = #srccount OUTPUT
select #srccount,#id,#tablename
fetch next from my_cursor
into #id,#tablename
end
close my_cursor;
deallocate my_cursor;
Thanks in advance
Try this,
SET NOCOUNT ON;
declare #q2 nvarchar(max) = '';
SELECT #q2 = #q2 + 'SELECT COUNT(*) AS cnt, ''' + tablename + ''' AS TableName FROM ' + tablename + ' (NOLOCK); '
FROM table1
--Print #q2
execute sp_executesql #q2

How to query current row's DB name in SQL server?

TableA exists in all 4 DBs, run this,
Use DB1
go
select CurrentDB=DB_NAME(), * From DB1..TableA union all
select CurrentDB=DB_NAME(), * From DB2..TableA union all
select CurrentDB=DB_NAME(), * From DB3..TableA union all
select CurrentDB=DB_NAME(), * From DB4..TableA
always got CurrentDB ='DB1'. is there a Simple way to get DB2,3,4 when the rows are pulling from non-DB1?
Trying to avoid hard code.
Create the same view in each database that returns the value of DB_NAME() as a column. Then, in the union, the each row will include the database name.
Try this
Use Master
set NOCOUNT ON;
Declare #db_name Varchar(12)
Declare #sql Varchar(1000)
Declare db_cursor CURSOR FOR
SELECT [name]
FROM sys.databases Where [name] like 'DB[123456789]'
Open db_cursor
Fetch Next FROM db_cursor INTO #db_name
if ##FETCH_STATUS = 0
begin
Select #sql = 'select ''' + #db_name + ''', * From ' + #db_name + '..TableA'
Fetch Next FROM db_cursor INTO #db_name
While ##FETCH_STATUS = 0
begin
select #sql = #sql + ' Union all select ''' +
#db_name + ''', * From ' + #db_name + '..TableA'
Fetch NEXT FROM db_cursor INTO #db_name
end
exec #sql
end
Close db_cursor
Deallocate db_cursor
Not tested, but basic idea is get all the matching db names. Build the sql statement, then exec it.

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

Error in Declaration of cursor

set #SQL=N' select #minTableId = MIN(id) from ' + #AcDB + '.dbo.vTblOfRollNo '
Declare Cursor For
EXEC SP_EXECUTESQL #SQL
if i have declared all the variables in above query but Declaration of cursor in above
query shows ERROR.
What is Solution?
In order to execute a cursor over dynamic SQL you must put the output of your dynamic sql into a temporary table and then cursor over the temporary table like this:
DECLARE #TableName NVARCHAR(100)
DECLARE #SQL NVARCHAR(1000)
CREATE TABLE #TempTABLE(email NVARCHAR(200))
SET #TableName='Users'
SELECT #SQL='INSERT INTO #TempTable SELECT email FROM ' + #TableName
EXEC (#SQL)
DECLARE MyCursor CURSOR FOR SELECT * FROM #TempTable
OPEN MyCursor
DECLARE #Email NVARCHAR(200)
FETCH NEXT FROM MyCursor INTO #Email
WHILE ##FETCH_STATUS = 0
BEGIN
PRINT 'Email = ' + #Email
FETCH NEXT FROM MyCursor INTO #Email
END
CLOSE MyCursor
DEALLOCATE MyCursor
DROP TABLE #TempTABLE
I dont think you need a cursor for this
try
DECLARE #AcDB VARCHAR(10),
#Sql NVARCHAR(MAX)
set #SQL=N' select MIN(id) from ' + #AcDB + '.dbo.vTblOfRollNo '
DECLARE #Temp TABLE(
MinID INT
)
INSERT INTO #Temp EXEC SP_EXECUTESQL #SQL
DECLARE #minTableId INT
SELECT TOP 1 #minTableId = MinID FROM #Temp
SELECT #minTableId
EDIT: Also here is the actual CURSOR documentation
DECLARE CURSOR (Transact-SQL)

Resources