SQL Server while loop and dynamic SQL - sql

I am trying to execute the dynamic SQL from SQL Server while loop. When the only print statement is executed query prints in the correct format but does not execute dynamic SQL with execute() or SP_EXECUTESQL. Please suggest.
Code:
WHILE( #count > 0 )
BEGIN
SELECT
#minID = MinID,
#maxID = MaxID
FROM
IDRange
WHERE
ID = #count
SET #QueryString = ' UPDATE
SD WITH(TABLOCk)
SET a = S4H.ID
FROM
A (nolock) S4H
INNER JOIN B SD on S4H.col = SD.col AND S4H.col1 = SD.col1
WHERE
SD.ID between ' + convert (varchar,#minID )+' AND '+convert (varchar,#maxID )+' AND
S4H.ID <= SD.ID AND
SD.ID <= S4h.ROWID'
SET #count= #count - 1'
print #QueryString
EXECUTE (#QueryString)
EXECUTE sp_executesql #QueryString, N'#minID INT,#maxID INT', #minID = #minID,#maxID= #maxID
--EXEC SP_EXECUTESQL #QueryString
--SELECT #Rcount= ##Rowcount
SET #count= #count - 1
END
END

There is an open ' at the end of SET #count= #count, remove that.
Use EXEC (#QueryString) to execute it, so it will look this this:
WHILE(#count > 0)
BEGIN
SELECT
#minID = MinID,
#maxID = MaxID
FROM IDRange
WHERE ID = #count;
SET #QueryString = ' UPDATE
SD WITH(TABLOCk)
SET a = S4H.ID
FROM
A (nolock) S4H
INNER JOIN B SD on S4H.col = SD.col AND S4H.col1 = SD.col1
WHERE
SD.ID between '+CONVERT(VARCHAR, #minID)+' AND '+CONVERT(VARCHAR, #maxID)+' AND
S4H.ID <= SD.ID AND
SD.ID <= S4h.ROWID';
PRINT #QueryString;
EXEC (#QueryString);
SET #count = #count - 1;
END;

-- Dynamic Query closing was not proper SET #count= #count - 1' Repeated twice which is not proper
WHILE( #count > 0 )
BEGIN
SELECT #minID = MinID, #maxID = MaxID
FROM IDRange
WHERE ID = #count
SET #QueryString = ' UPDATE
SD WITH(TABLOCk)
SET a = S4H.ID
FROM
A (nolock) S4H
INNER JOIN B SD on S4H.col = SD.col AND S4H.col1 = SD.col1
WHERE
SD.ID BETWEEN ' + convert (varchar,#minID )+' AND '+convert (varchar,#maxID )+' AND
S4H.ID <= SD.ID AND
SD.ID <= S4h.ROWID'
PRINT #QueryString
EXECUTE (#QueryString)
SET #count= #count - 1
END

Related

How to insert varchar variable in dynamic sql query

I have a query with a select statement in a loop and at the same time I want to insert a varchar variable and selected value into a temporary table, but I get an error like:
Msg 207, Level 16, State 1, Line 2
Invalid column name 'SP419001_SID'
This SP419001_SID is the value contained in the varchar variable #dbName.
This is my query:
CREATE TABLE #tempCounter
(
dbName1 varchar(max),
counterNumber1 int
)
DECLARE
#counter INT = 1,
#max INT = 0,
#dbName VARCHAR(100),
#count INT = 0,
#SQLTEXT VARCHAR(MAX),
#counterNumber VARCHAR(10)
SELECT #max = COUNT(id) FROM #tempPnamePadd
WHILE #counter <= #max
BEGIN
SET #dbName='';
-- Do whatever you want with each row in your table variable filtering by the Id column
SELECT #dbName = name
FROM #tempPnamePadd
WHERE Id = #counter
PRINT #dbName
SET #SQLTEXT =
--SELECT distinct PN.NAME_FORMAT_CODE, NAME_BUSINESS, INDIVIDUAL_FIRST, A.ADDRESS_ID, A.ADDR_LINE_1, A.ADDR_LINE_2, A.ADDR_LINE_3, A.CITY, A.STATE
'DECLARE #dbn VARCHAR(200)
SET #dbn ='+ #dbName +';
INSERT INTO #tempCounter
(dbname1, counternumber1)
SELECT #dbn ,
(SELECT count(*)
FROM '+ #dbName +'.dbo.PRELA PR
INNER JOIN '+ #dbName +'.dbo.PNAME PN
ON PR.NAME_ID = PN.NAME_ID
INNER JOIN '+ #dbName +'.dbo.PNALK NK
ON PN.NAME_ID = NK.NAME_ID
INNER JOIN '+ #dbName +'.dbo.PADDR A
ON NK.ADDRESS_ID = A.ADDRESS_ID
WHERE (NAME_FORMAT_CODE=''B'' and NAME_BUSINESS like ''%BN'') OR
(NAME_FORMAT_CODE <> ''B'' and INDIVIDUAL_FIRST = ''John'') OR
(ADDR_LINE_1=''WELLS STREET'' AND CITY=''HOLLYWOOD'' AND STATE=''IA'')
)
'
--PRINT #SQLTEXT
EXEC (#SQLTEXT)
SET #counter = #counter + 1
END
This is very likely not the most efficient way to do this; most likely you should be using STRING_AGG or FOR XML PATH and STUFF to do this.
Anyway, you need to parametrise your variable, and quote your dynamic objects. This results in the below:
CREATE TABLE #tempCounter (dbName1 sysname,
counterNumber1 int);
DECLARE #counter int = 1,
#max int = 0,
#dbName sysname,
#count int = 0,
#SQLTEXT nvarchar(MAX),
#counterNumber varchar(10);
SELECT #max = COUNT(id)
FROM #tempPnamePadd;
WHILE #counter <= #max
BEGIN
SET #dbName = '';
-- Do whatever you want with each row in your table variable filtering by the Id column
SELECT #dbName = name
FROM #tempPnamePadd
WHERE Id = #counter;
PRINT #dbName;
SET #SQLTEXT = N'INSERT INTO #tempCounter
(dbname1, counternumber1)
SELECT #dbn ,
(SELECT count(*)
FROM ' + QUOTENAME(#dbName) + N'.dbo.PRELA PR
INNER JOIN ' + QUOTENAME(#dbName) + N'.dbo.PNAME PN
ON PR.NAME_ID = PN.NAME_ID
INNER JOIN ' + QUOTENAME(#dbName) + N'.dbo.PNALK NK
ON PN.NAME_ID = NK.NAME_ID
INNER JOIN ' + QUOTENAME(#dbName) + N'.dbo.PADDR A
ON NK.ADDRESS_ID = A.ADDRESS_ID
WHERE (NAME_FORMAT_CODE=''B'' and NAME_BUSINESS like ''%BN'') OR
(NAME_FORMAT_CODE <> ''B'' and INDIVIDUAL_FIRST = ''John'') OR
(ADDR_LINE_1=''WELLS STREET'' AND CITY=''HOLLYWOOD'' AND STATE=''IA'')
)
';
--PRINT #SQLTEXT
EXEC sp_executesql #SQLTEXT, N'#dbn sysname', #dbn = #dbName;
SET #counter = #counter + 1;
END;
Note I have also changed some of your data types.
You did not quote around #dbName in your dynamic query.
So instead of
SET #dbn ='SP419001_SID';
you get
SET #dbn =SP419001_SID;
Do
'DECLARE #dbn VARCHAR(200)
SET #dbn ='''+ #dbName +''';
INSERT INTO #tempCounter
...'

SQL Server stored procedure running in infinite loop

I am running a stored procedure which is running infinitely.
I have used a while loop that seems to be running without ever ending.
CREATE PROCEDURE ABC
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Id INT;
DECLARE #iter INT = 1;
DECLARE #iterMax INT;
DECLARE #psubject VARCHAR(100);
DECLARE #pbody NVARCHAR(MAX);
DECLARE #pSendTo NVARCHAR(MAX);
DECLARE #pProfile VARCHAR(MAX);
IF OBJECT_ID('tempdB..#temp') IS NOT NULL
DROP TABLE #temp;
SET #pProfile = 'Test';
IF ((SELECT COUNT(*)
FROM [Table_A] R
JOIN [Table_B] T ON R.Id = T.r_Id
WHERE R.[Date] <= (DATEADD(DAY, -1, GETDATE()))
AND T.[Sent_Flag] IS NULL) >= 1)
BEGIN
SELECT IDENTITY(int, 1, 1) AS RecId,
[r_id] * 1 AS Id
INTO #temp
FROM [Table_A] R
JOIN [Table_B] T ON R.Id = T.r_Id
WHERE R.[Date] <= (DATEADD(DAY, -1, GETDATE()))
AND T.[Sent_Flag] IS NULL;
BEGIN
SET #iterMax = (SELECT COUNT(*)FROM #temp);
WHILE (#iter <= #iterMax)
BEGIN
SET #psubject = 'HIIII'; /*this is in HTML example */
SET #pbody = 'You got one email';
IF ((SELECT COUNT(*)
FROM [Table_B]
WHERE R_Id = (SELECT Id FROM #temp WHERE RecId = #iter)
AND [Mail1_Flag] = 'Y'
AND [Mail2_Flag] = 'Y') = 1)
BEGIN
IF ((SELECT COUNT(*)
FROM [Table_A] R
JOIN [Table_B] T ON R.Id = T.r_Id
WHERE R_Id = (SELECT Id FROM #temp WHERE RecId = #iter)
AND R.[Date] <= (DATEADD(DAY, -1, GETDATE()))
AND T.[Sent_Flag] IS NULL) = 1)
BEGIN
SET #pSendTo = N'ABC#gmail.com';
EXEC msdb.dbo.sp_send_dbmail #profile_name = #pProfile,
#body = #pbody,
#subject = #psubject,
#recipients = #pSendTo,
#body_format = 'HTML';
END;
UPDATE [Table_B]
SET [Sent_Flag] = 'Y'
WHERE [Id] IN (SELECT Id FROM #temp WHERE RecId = #iter);
END;
END;
SET #iter = #iter + 1;
END;
END;
IF OBJECT_ID('tempd..#temp') IS NOT NULL
DROP TABLE #temp;
END;
This program is checking that if date is more than 24 hours then it will send a mail correspondingly. I am able to trigger a mail. But I am getting multiple mails. Like the loop is running infinitely and getting same mail multiple times and the sent_Flag column is initial NULL and after a mail is sent it sholud update to 'Y' but it is also not updating to 'Y' after mail is triggered.
Please help to resolve this issue. Thank you
You are not incrementing the counter inside the loop:
UPDATE [Table_B]
SET [Sent_Flag] = 'Y'
WHERE [Id] IN (SELECT Id FROM #temp WHERE RecId = #iter);
END; --this is the END of the first IF BEGIN
END; --this is the END of the WHILE BEGIN
SET #iter = #iter + 1; --and here you update the counter, which will never be reached
If you don't increment the counter inside the loop, the loop will run infinitely, since the loop condition will always be true.

convert the sql statements to stored procedure

I am trying to convert the below sql statements to stored procedure, which should return me list of delete statements from output parameter.
At present this statement print the sql delete statements on message box of sql server, but i need to make a stored procedure.
The input parameters provide are the table name and the primary key column name and one output parameter which will give the list of sql delete statements.
Can someone help!
if object_id('tempdb..#tmp') is not null
drop table #tmp;
create table #tmp (id int, tablename varchar(256), lvl int, ParentTable varchar(256));
insert into #tmp
exec dbo.usp_SearchFK #table='dbo.M', #debug=0;
declare #where varchar(max) ='where M.id=2' -- if #where clause is null or
empty, it will delete tables as a whole with the right order
declare #curFK cursor, #fk_object_id int;
declare #sqlcmd varchar(max)='', #crlf char(2)=char(0x0d)+char(0x0a);
declare #child varchar(256), #parent varchar(256), #lvl int, #id int;
declare #i int;
declare #t table (tablename varchar(128));
declare #curT cursor;
if isnull(#where, '')= ''
begin
set #curT = cursor for select tablename, lvl from #tmp order by lvl desc
open #curT;
fetch next from #curT into #child, #lvl;
while ##fetch_status = 0
begin -- loop #curT
if not exists (select 1 from #t where tablename=#child)
insert into #t (tablename) values (#child);
fetch next from #curT into #child, #lvl;
end -- loop #curT
close #curT;
deallocate #curT;
select #sqlcmd = #sqlcmd + 'delete from ' + tablename + #crlf from #t ;
print #sqlcmd;
end
else
begin
declare curT cursor for
select lvl, id
from #tmp
order by lvl desc;
open curT;
fetch next from curT into #lvl, #id;
while ##FETCH_STATUS =0
begin
set #i=0;
if #lvl =0
begin -- this is the root level
select #sqlcmd = 'delete from ' + tablename from #tmp where id =
#id;
end -- this is the roolt level
while #i < #lvl
begin -- while
select top 1 #child=TableName, #parent=ParentTable from #tmp
where id <= #id-#i and lvl <= #lvl-#i order by lvl desc, id desc;
set #curFK = cursor for
select object_id from sys.foreign_keys
where parent_object_id = object_id(#child)
and referenced_object_id = object_id(#parent)
open #curFK;
fetch next from #curFk into #fk_object_id
while ##fetch_status =0
begin -- #curFK
if #i=0
set #sqlcmd = 'delete from ' + #child + #crlf +
'from ' + #child + #crlf + 'inner join ' + #parent ;
else
set #sqlcmd = #sqlcmd + #crlf + 'inner join ' + #parent ;
;with c as
(
select child =
object_schema_name(fc.parent_object_id)+'.' +
object_name(fc.parent_object_id), child_col=c.name
, parent =
object_schema_name(fc.referenced_object_id)+'.' +
object_name(fc.referenced_object_id), parent_col=c2.name
, rnk = row_number() over (order by (select null))
from sys.foreign_key_columns fc
inner join sys.columns c
on fc.parent_column_id = c.column_id
and fc.parent_object_id = c.object_id
inner join sys.columns c2
on fc.referenced_column_id = c2.column_id
and fc.referenced_object_id = c2.object_id
where fc.constraint_object_id=#fk_object_id
)
select #sqlcmd =#sqlcmd + case rnk when 1 then ' on '
else ' and ' end
+ #child +'.'+ child_col +'=' + #parent +'.' +
parent_col
from c;
fetch next from #curFK into #fk_object_id;
end --#curFK
close #curFK;
deallocate #curFK;
set #i = #i +1;
end --while
print #sqlcmd + #crlf + #where + ';';
print '';
fetch next from curT into #lvl, #id;
end
close curT;
deallocate curT;
end
go

Use #variable in COLUMN name in SQL SERVER 2012

Here, I've used SUM function on TRx1 column.
I've TRx2,3,4,..53 Columns in the table.
I want to display all the columns using loop.
DECLARE #flag INT;
SET #flag = 1;
WHILE #flag <= 2
BEGIN
select TOP 5 sd.OutletBPID, md.Product, SUM(TRx1)
from sdata as sd, md, oa
where sd.PSetID = md.PsetID
group by sd.OutletBPID, md.Product;
SET #flag = #flag + 1;
END;
The following code i did but it shows error: "Invalid Column Name"
DECLARE #flag INT;
SET #flag = 1;
WHILE #flag <= 2
BEGIN
select TOP 5 sd.OutletBPID, md.Product, SUM(TRx#flag)
from sdata as sd, md, oa
where sd.PSetID = md.PsetID
group by sd.OutletBPID, md.Product;
SET #flag = #flag + 1;
END;
You need dynamic sql
DECLARE #flag INT,
#sql varchar(8000)=''
SET #flag = 1;
WHILE #flag <= 2
BEGIN
SET #sql = 'select TOP 5 sd.OutletBPID, md.Product, SUM(TRx'+cast(#flag as varchar(20))+')
from sdata as sd, md, oa
where sd.PSetID = md.PsetID
group by sd.OutletBPID, md.Product'
exec (#sql)
SET #flag = #flag + 1;
END;

How to use a variable in SQL statement From Line

I am trying to create a procedure that allows for a variable to be used as a table name.
Example:
Select Temp1, Temp2
From #var
The #var has the correct table name but changes with each iteration through the while loop.
-- Above sets up all Variables
WHILE #Count >= #I
BEGIN
SET #ObjectID = (SELECT ObjectID FROM #TmpTable WHERE ID = #I)
SET #TableName = (SELECT TableName FROM #TmpTable WHERE ID = #I)
IF #I = 8
BEGIN
SELECT *
INTO ##TMPTable
FROM #TableName
-- Additional Processing
END
END
DECLARE
#SQLString varchar(max),
#TempTableName varchar(100)
SET #TempTableName = '##TMPTable' + cast( ##spid AS varchar(5))
WHILE #Count >= #I
BEGIN
SET #ObjectID = (SELECT ObjectID FROM #TmpTable WHERE ID = #I)
SET #TableName = (SELECT TableName FROM #TmpTable WHERE ID = #I)
IF #I = 8
BEGIN
set #SQLString = '
SELECT *
INTO ' + #TempTableName + '
FROM ' + #TableName
EXECUTE ( #SQLString )
EXECUTE ( 'SELECT * from ' + #TempTableName)
-- Additional Processing
END
END