looping through a dynamic list in sql - sql

I am writing a stored procedure to read a list of int values that is dynamic (a parameter to the procedure). Once I read this list I need to do an insert to another table for each value in the list. I am not very good at sql. Can you please help me?
This is what I have done so far.
CREATE PROCEDURE [dbo].[FunctionInsert]
(
#CONTEXTCODEID INTEGER,
#MASTERCASEID INTEGER,
#LETTERCODEIDS VARCHAR(50)
)
IF #LETTERCODEIDS <> '0'
BEGIN
WITH cd AS
(
SELECT 1 AS first, CHARINDEX(',', #LETTERCODEIDS , 1) AS next
UNION ALL
SELECT next + 1, CHARINDEX(',', #LETTERCODEIDS , next + 1)
FROM cd
WHERE next > 0
),
lid AS
(
SELECT CAST(SUBSTRING(#LETTERCODEIDS , first, CASE next WHEN 0 THEN LEN(#LETTERCODEIDS ) + 1 ELSE next END - first)AS INT) AS id
FROM cd
)
SELECT * FROM
(
SELECT DISTINCT id
FROM lid
) l
I am getting the list of values in id as 1,2,3 if i EXEC FunctionInsert (#LETTERCODEIDS = '1,2,3')
Now I need to loop through these and do an insert into another table.
INSERT INTO [dbo].CaseLetters
(
ContextCodeID,
MasterCaseID,
LetterCodeID
)
VALUES
(
#CONTEXTCODEID,
#MASTERCASEID ,
--My values from the list need to go here
)
I am not sure how to proceed.

When I find myself wanting to loop through a set of values in SQL I usually end up using a cursor.
Suppose your stored procedure is populating a table called #tmp_id
DECLARE #ID INT
DECLARE my_cursor CURSOR FOR
SELECT ID FROM #tmp_id
OPEN my_cursor
FETCH NEXT FROM my_cursor INTO #ID
WHILE ##FETCH_STATUS == 0
BEGIN
-- This is the body of the loop where your logic will go
-- Every value in the set returned by SELECT ID FROM #tmp_id will
-- Be bound to the variable #ID for one iteration of this loop
FETCH NEXT FROM my_cursor INTO #ID
END
CLOSE my_cursor
DEALLOCATE my_cursor
Let me know if I can clarify anything.

Related

Procedure with Cursor for E-Mail

i have a table with following things inside:
Name E-Mail
Trump, Donald Null
Now i have to do a Procedure with a cursor, which creates a e-mail out of the name of the guy.
f.e. donald.trump#usa.com, also it should update the e-mail table.
How can i do this?
Please check this example created as per your requirement.
CREATE PROCEDURE [NameProcedure]
AS
BEGIN
DECLARE #table AS TABLE
(
Name NVARCHAR(200),
Email NVARCHAR(200) NULL
)
INSERT INTO #table(Name) VALUES('Trump, Donald'),('barack, obama')
DECLARE
#nameemail NVARCHAR(20)
DECLARE cursor_procedure CURSOR
FOR SELECT
REPLACE(Name,',','') AS Name
FROM
(
SELECT CONCAT(LEFT(Name,CHARINDEX(',',Name)),'.',RIGHT(Name,CHARINDEX(',',Name)),'#usa.com') Name
FROM #table
) AS Result
OPEN cursor_procedure;
FETCH NEXT FROM cursor_procedure INTO
#nameemail
WHILE ##FETCH_STATUS = 0
BEGIN
SELECT #nameemail AS Name
FETCH NEXT FROM cursor_procedure INTO
#nameemail
END;
CLOSE cursor_procedure;
DEALLOCATE cursor_procedure;
END
-- Run the store procedure
EXEC [NameProcedure]
Output
For cursor related you can read this
https://www.sqlservertutorial.net/sql-server-stored-procedures/sql-server-cursor/
Assuming you are using SQL server
select CONCAT (SUBSTRING(name, CHARINDEX(',', name) + 1, LEN(name)) , '.' , LEFT(name, CHARINDEX(',', name) - 1) , '#usa.com') from
(
select 'Trump, Donald' as name
) tab

Using a for loop in sql procedure

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

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.

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.