Using a for loop in sql procedure - sql

I want to check out #deemeturu in sql prosudure and check in where condition. For example, I want to continue where (# odemetur = 1 OR # odemetur = 2 OR # odemetur = 3 OR # odemetur = 4). How can we find a solution to this problem?
NOTE: #odemetur changes the number of indices. '1,2,3,4' is not static
alter PROCEDURE sp_siparis
(
#PageNo INT,
#RowCountPerPage INT,
#adsoyadfilter nvarchar(50),
#toplamtutarfilter decimal,
#tarihfilter datetime,
#odemeturu nvarchar(500) = '1,2,3,4'
)
AS
SELECT
u.AdiSoyadi as AdSoyad,
s.OdemeTipAdi as OdemeTipAdi,
sd.Adi as SiparisDurumAdi,
s.OlusturmaTarihi as OlusturmaTarihi,
s.GenelToplam as GenelToplam
FROM
Siparis as s with(NOLOCK)
inner join
SiparisDurum as sd with(NOLOCK) on s.Durumu=sd.Id
inner join
Uye as u with(NOLOCK) on s.Uye_Id=u.Id
WHERE
(u.AdiSoyadi LIKE '%' + #adsoyadfilter + '%') OR (s.GenelToplam = #toplamtutarfilter) OR (s.OlusturmaTarihi = #tarihfilter)
ORDER BY
s.Id OFFSET (#PageNo) ROWS FETCH NEXT #RowCountPerPage ROWS ONLY
GO

you may add this conditions in where clause
or
you may use Cursor and in while use if to pass specific records
DECLARE data_Cursor Cursor For
-- SELECT data here
OPEN data_Cursor
FETCH NEXT FROM data_Cursor INTO
-- add variables here
WHILE ##FETCH_STATUS = 0
BEGIN
IF -- your if condition
BEGIN
-- your logic here
END
FETCH NEXT FROM data_Cursor INTO
-- add variables here
END
CLOSE data_Cursor
DEALLOCATE data_Cursor

Related

Combine results of multiple queries as one result in a SQL Server stored procedure

I need some help with a stored procedure. It contains a loop which runs a Select query. What I get is 3 tables with result if it loops thrice. How can I combine the results as one table?
The procedure is as below:
CREATE PROCEDURE [dbo].[spGetRndQuestions]
#ExamCode Nvarchar(60)
AS
BEGIN
Declare #NosQues Int, #Catgry nvarchar(50)
DECLARE CategCursor CURSOR FOR
(Select Category From tblExamDetail Where ExamCode = #ExamCode)
OPEN CategCursor
FETCH NEXT FROM CategCursor INTO #Catgry
WHILE ##FETCH_STATUS = 0
BEGIN
SET #NosQues = (Select NoOfQues from tblExamDetail Where ExamCode=#ExamCode AND Category=#Catgry)
SELECT TOP(#NosQues) QM.QuestionID, QM.QuestionDesc, QM.QuestionMarks, QM.Answer1, QM.Answer2, QM.Answer3, QM.Answer4 FROM tblQuestionMaster QM
INNER JOIN tblExamMaster EM ON QM.Dept = EM.Dept AND QM.Location = EM.Location AND QM.QuesModule = EM.ExamModule
Where EM.ExamCode=#ExamCode AND QM.Category =#Catgry
Order by NEWID()
/*SELECT TOP (#NosQues) QuestionID,QuestionDesc,Answer1,Answer2,Answer3,Answer4,QuestionMarks from [dbo].[tblQuestionMaster] Where Category=#Catgry AND
Order by NEWID() */
FETCH NEXT FROM CategCursor INTO #Catgry
END
CLOSE CategCursor
DEALLOCATE CategCursor
END
Thanks, your help is truly appreciated.
Create the table variable in start of your SP of appropriate structure of your return table. In each iteration insert selected data to that table. After deallocating cursor select from that table.
CREATE PROCEDURE [dbo].[spGetRndQuestions]
#ExamCode Nvarchar(60) AS
BEGIN
Declare #NosQues Int, #Catgry nvarchar(50)
DECLARE #tbl TABLE(QuestionID int, QuestionDesc ....)
DECLARE CategCursor CURSOR FOR (Select Category From tblExamDetail Where ExamCode=#ExamCode)
OPEN CategCursor
FETCH NEXT FROM CategCursor INTO #Catgry
WHILE ##FETCH_STATUS = 0
BEGIN
SET #NosQues = (Select NoOfQues from tblExamDetail Where ExamCode=#ExamCode AND Category=#Catgry)
INSERT INTO #tbl
SELECT TOP(#NosQues) QM.QuestionID, QM.QuestionDesc, QM.QuestionMarks, QM.Answer1, QM.Answer2, QM.Answer3, QM.Answer4 FROM tblQuestionMaster QM
INNER JOIN tblExamMaster EM ON QM.Dept = EM.Dept AND QM.Location = EM.Location AND QM.QuesModule = EM.ExamModule
Where EM.ExamCode=#ExamCode AND QM.Category =#Catgry
Order by NEWID()
/*SELECT TOP (#NosQues) QuestionID,QuestionDesc,Answer1,Answer2,Answer3,Answer4,QuestionMarks from [dbo].[tblQuestionMaster] Where Category=#Catgry AND
Order by NEWID() */
FETCH NEXT FROM CategCursor INTO #Catgry
END
CLOSE CategCursor
DEALLOCATE CategCursor
SELECT * FROM #tbl
END
Hamlet does answer the question. However, the query you posted could be optimized to eliminate the need for the cursor or table variable. The following code should do that nicely:
CREATE PROCEDURE [dbo].[spGetRndQuestions]
#ExamCode Nvarchar(60)
AS
SELECT
--A.[category],
B.*
FROM tblExamDetail A
CROSS APPLY (
SELECT TOP (A.[NoOfQues])
QM.QuestionID,QM.QuestionDesc,QM.QuestionMarks,
QM.Answer1,QM.Answer2,QM.Answer3,QM.Answer4
FROM tblQuestionMaster QM
INNER JOIN tblExamMaster EM
ON QM.Dept = EM.Dept
AND QM.Location = EM.Location
AND QM.QuesModule = EM.ExamModule
WHERE EM.ExamCode = A.[ExamCode]
AND QM.Category = A.[Category]
ORDER BY NEWID()
) B
WHERE A.[ExamCode] = #ExamCode

Loop through all the rows of a temp table and call a stored procedure for each row

I have declared a temp table to hold all the required values as follows:
DECLARE #temp TABLE
(
Password INT,
IdTran INT,
Kind VARCHAR(16)
)
INSERT INTO #temp
SELECT s.Password, s.IdTran, 'test'
from signal s inner join vefify v
on s.Password = v.Password
and s.IdTran = v.IdTran
and v.type = 'DEV'
where s.[Type] = 'start'
AND NOT EXISTS (SELECT * FROM signal s2
WHERE s.Password = s2.Password
and s.IdTran = s2.IdTran
and s2.[Type] = 'progress' )
INSERT INTO #temp
SELECT s.Password, s.IdTran, 'test'
FROM signal s inner join vefify v
on s.Password = v.Password
and s.IdTran = v.IdTran
and v.type = 'PROD'
where s.[Type] = 'progress'
AND NOT EXISTS (SELECT * FROM signal s2
WHERE s.Password = s2.Password
and s.IdTran = s2.IdTran
and s2.[Type] = 'finish' )
Now i need to loop through the rows in the #temp table and and for each row call a sp that takes all the parameters of #temp table as input.
How can I achieve this?
you could use a cursor:
DECLARE #id int
DECLARE #pass varchar(100)
DECLARE cur CURSOR FOR SELECT Id, Password FROM #temp
OPEN cur
FETCH NEXT FROM cur INTO #id, #pass
WHILE ##FETCH_STATUS = 0 BEGIN
EXEC mysp #id, #pass ... -- call your sp here
FETCH NEXT FROM cur INTO #id, #pass
END
CLOSE cur
DEALLOCATE cur
Try returning the dataset from your stored procedure to your datatable in C# or VB.Net. Then the large amount of data in your datatable can be copied to your destination table using a Bulk Copy. I have used BulkCopy for loading large datatables with thousands of rows, into Sql tables with great success in terms of performance.
You may want to experiment with BulkCopy in your C# or VB.Net code.
something like this?
DECLARE maxval, val, #ind INT;
SELECT MAX(ID) as maxval FROM table;
while (ind <= maxval ) DO
select `value` as val from `table` where `ID`=ind;
CALL fn(val);
SET ind = ind+1;
end while;
You can do something like this
Declare #min int=0, #max int =0 --Initialize variable here which will be use in loop
Declare #Recordid int,#TO nvarchar(30),#Subject nvarchar(250),#Body nvarchar(max) --Initialize variable here which are useful for your
select ROW_NUMBER() OVER(ORDER BY [Recordid] ) AS Rownumber, Recordid, [To], [Subject], [Body], [Flag]
into #temp_Mail_Mstr FROM Mail_Mstr where Flag='1' --select your condition with row number & get into a temp table
set #min = (select MIN(Rownumber) from #temp_Mail_Mstr); --Get minimum row number from temp table
set #max = (select Max(Rownumber) from #temp_Mail_Mstr); --Get maximum row number from temp table
while(#min <= #max)
BEGIN
select #Recordid=Recordid, #To=[To], #Subject=[Subject], #Body=Body from #temp_Mail_Mstr where Rownumber=#min
-- You can use your variables (like #Recordid,#To,#Subject,#Body) here
-- Do your work here
set #min=#min+1 --Increment of current row number
END
You always don't need a cursor for this. You can do it with a while loop. You should avoid cursors whenever possible. While loop is faster than cursors.

TSQL: Using a Table in a Variable in a Function

I'm trying to do a select from a table that will need to be in a variable. I'm working with tables that are dynamically created from an application. The table will be named CMDB_CI_XXX, where XXX will be an integer value based on a value in another table. The ultimate goal is to get the CI Name from the table.
I've tried passing the pieces that make up the table name to a function and string them together and then return the name value, but I'm not allowed to use an EXEC statement in a function.
This is what I want to execute to get the name value back:
Select [Name] from 'CMDB_CI_' + C.CI_TYPE_ID + Where CI_ID = c.CI_ID
This is the code in the SP that I'd like to use the function in to get the name value:
SELECT
CI_ID,
C.CI_TYPE_ID,
CI_CUSTOM_ID,
STATUS,
CI_TYPE_NAME,
--(Select [Name] from CMDB_CI_ + C.CI_TYPE_ID + Where CI_ID = c.CI_ID)
FROM [footprints].[dbo].[CMDB50_CI_COMMON] c
join [footprints].[dbo].[CMDB50_CI_TYPE] t
on c.CI_TYPE_ID = t.CI_TYPE_ID
where status <> 'retired'
order by CI_TYPE_NAME
I'm not sure what to do with this. Please help?
Thanks,
Jennifer
-- This part would be a SP parameter I expect
DECLARE #tableName varchar(100)
SET #tableName = 'CMDB_CI_508'
-- Main SP code
DECLARE #sqlStm VARCHAR(MAX)
SET #sqlStm = 'SELECT *
FROM '+ #tableName
EXEC (#sqlStm)
Fiddle http://sqlfiddle.com/#!3/436a7/7
First off, yes, I know it's a bad design. I didn't design it. It came with the problem tracking software that my company bought for our call center. So I gave up altogether on the approach I was going for and used a cursor to pull all the the names from the various tables into one temp table and then used said temp table to join to the original query.
ALTER Proc [dbo].[CI_CurrentItems]
As
Declare #CIType nvarchar(6)
Declare #Qry nvarchar(100)
/*
Create Table Temp_CI
( T_CI_ID int,
T_CI_Type_ID int,
T_Name nvarchar(400)
)
*/
Truncate Table Temp_CI
Declare CI_Cursor Cursor For
select distinct CI_TYPE_ID FROM [footprints].[dbo].[CMDB50_CI_COMMON]
where STATUS <> 'Retired'
Open CI_Cursor
Fetch Next from CI_Cursor into #CIType
While ##FETCH_STATUS = 0
BEGIN
Set #Qry = 'Select CI_ID, CI_Type_ID, Name from Footprints.dbo.CMDB50_CI_' + #CIType
Insert into Temp_CI Exec (#Qry)
Fetch Next from CI_Cursor into #CIType
END
Close CI_Cursor
Deallocate CI_Cursor
SELECT CI_ID,
C.CI_TYPE_ID,
CI_CUSTOM_ID,
STATUS,
CI_TYPE_NAME,
T_Name
FROM [footprints].[dbo].[CMDB50_CI_COMMON] c
JOIN [footprints].[dbo].[CMDB50_CI_TYPE] t
ON c.CI_TYPE_ID = t.CI_TYPE_ID
JOIN Temp_CI tc
ON c.CI_ID = tc.T_CI_ID
AND t.CI_TYPE_ID = tc.T_CI_TYPE_ID
WHERE STATUS <> 'retired'
ORDER BY CI_TYPE_NAME

SQL while loop with Temp Table

I need to create a temporary table and then update the original table. Creating the temporary table is not a problem.
create table #mod_contact
(
id INT IDENTITY NOT NULL PRIMARY KEY,
SiteID INT,
Contact1 varchar(25)
)
INSERT INTO #mod_contact (SiteID, Contact1)
select r.id, r.Contact from dbo.table1 r where CID = 142
GO
Now I need to loop through the table and update r.contact = SiteID + r.contact
I have never used a while loop before and can't seem to make any examples I have seen work.
You can do this in multiple ways, but I think you're looking for a way using a cursor.
A cursor is sort of a pointer in a table, which when incremented points to the next record. ( it's more or less analogeous to a for-next loop )
to use a cursor you can do the following:
-- DECLARE the cursor
DECLARE CUR CURSOR FAST_FORWARD READ_ONLY FOR SELECT id, siteId, contract FROM #mod_contract
-- DECLARE some variables to store the values in
DECLARE #varId int
DECLARE #varSiteId int
DECLARE #varContract varchar(25)
-- Use the cursor
OPEN CUR
FETCH NEXT FROM CUR INTO #varId, #varSiteId, #varContract
WHILE ##FETCH_STATUS = 0
BEGIN
UPDATE dbo.table1
SET contract = #varSiteId + #varContract -- It might not work due to the different types
WHERE id = #varId
FETCH NEXT FROM CUR INTO #varId, #varSiteId, #varContract
END
CLOSE CUR
DEALLOCATE CUR
It's not the most efficient way to get this done, but I think this is what you where looking for.
Hope it helps.
Use a set based approach - no need to loop (from the little details):
UPDATE
r
SET
r.Contact = m.SiteID + r.Contact
FROM
table1 r
INNER JOIN
#mod_contact m
ON m.id=r.id
Your brain wants to do this:
while records
update(i); //update record i
records = records + 1
end while
SQL is set based and allows you to take a whole bunch of records and update them in a single command. The beauty of this is you can use the WHERE clause to filter certain rows that are not needed.
As others have mentioned, learning how to do loops in SQL is generally a bad idea; however, since you're trying to understand how to do something, here's an example:
DECLARE #id int
SELECT #ID =1
WHILE #ID <= (SELECT MAX(ID) FROM table_1)
-- while some condition is true, then do the following
--actions between the BEGIN and END
BEGIN
UPDATE table_1
SET contact = CAST(siteID as varchar(100)) + contact
WHERE table_1.CID = #ID
--increment the step variable so that the condition will eventually be false
SET #ID = #ID + 1
END
--do something else once the condition is satisfied
PRINT 'DONE!! Don't try this in production code...'
Try this one:
-- DECLARE the cursor
DECLARE CUR CURSOR FAST_FORWARD READ_ONLY FOR SELECT column1,column2 FROM table
-- DECLARE some variables to store the values in
DECLARE #varId int
DECLARE #varSiteId int
--DECLARE #varContract varchar(25)
-- Use the cursor
OPEN CUR
FETCH NEXT FROM CUR INTO #varId, #varSiteId
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT *
FROM Table2
WHERE column1 = #varId
AND column2 = #varSiteId
FETCH NEXT FROM CUR INTO #varId, #varSiteId
END
CLOSE CUR
DEALLOCATE CUR
need to create a temporary table and then up date the original table.
Why use a temporary table at all? Your CID column doesn't appear in the temporary table, so I don't see how you can successfully update the original table using SiteID, unless there is only one row where CID = 142 in which using a temp table is definitely overkill.
You can just do this:
UPDATE dbo.table1
SET contact = SiteID + contact
WHERE CID = 142;
Here's a related example which may help getting you to 'think in SQL':
UPDATE T
SET A = B, B = A;
Assuming A and B are of the same type, this would successfully swap their values.

SQL Server 2000 - Breaking out of a loop

I am not good at SQL Server 2000. I have a comma-delimited list of ids. I need to see if that ID exists in a table. If it does, I want to break out of the loop with that ID saved in a variable that I can use in my stored procedure. This is what I am trying right now:
DECLARE #coreID INT
SET #coreID=NULL
DECLARE #itemID NVARCHAR(50)
DECLARE itemCursor CURSOR LOCAL FAST_FORWARD FOR
SELECT [String] AS 'itemID' FROM dbo.SplitListIntoTable(#myIDs)
OPEN itemCursor
FETCH NEXT FROM itemCursor INTO #itemID
WHILE ##FETCH_STATUS = 0 BEGIN
-- If #itemID EXISTS IN MyTable set #coreID=#itemID and Break. How do I do this?
FETCH NEXT FROM itemCursor INTO #itemID
END
CLOSE itemCursor
DEALLOCATE itemCursor
Thank you!
Ideally, you shouldn't use a cursor as performance won't be great. If you can do it as a set-based statement, do that instead, maybe like this:
SELECT TOP 1 #CoreID = [String]
FROM dbo.SplitListIntoTable(#myIDs) x
JOIN MyTable t ON x.[String] = t.ID
However, if you have a real reason to use a cursor, you can use the BREAK statement to break out of a WHILE loop
e.g.
WHILE ##FETCH_STATUS = 0
BEGIN
IF EXISTS(SELECT * FROM MyTable WHERE Id = #ItemID)
BEGIN
SET #CoreId = #ItemId
BREAK
END
FETCH NEXT FROM itemCursor INTO #itemID
END
I don't know how to do this using a cursor, but I supect you can do this much better (faster) with a a join. If the output of dbo.SplitListIntoTable(#myIDs) is actually an odered table, then you can output a table with another column what is say the string numer, 1, 2, 3, etc...
(I don't have sql in front of me to test this but something like)
create table t(itemNum int identity, itemId nvarchar(max))
insert into t (item id) select 1 from dbo.SplitListIntoTable(#myIDs)
Then join the two and take the top one
set #coreID =
select top 1 #itemID
from MyTable m
inner join t t.itemid = m.itemid
order by m.itemNum asc
of course you could use a CTE, table var or temp table too.