SQL While Loop Insert with values from another table - sql

I am trying to create a SQL While loop that will update a temp table with values from another table. Values from the other table:
477286
560565
499330
391827
127375
526354
501736
357359
410433
500946
261297
377667
135931
235691
247239
143672
548752
471945
...
Wrote the following, however, it only inserts the last value multiple times over.
Here is the code:
USE Reports
GO
CREATE TABLE #TempTable (CreatedByID int, LastUpdatedByID int, ID int,
AlertDE int, Alert char(50), StartDTTM datetime, EndDTTM datetime,
IsInactiveFLAG char(1),AlertDetails char(1));
DECLARE #numrows INT
SELECT #numrows = COUNT(*) FROM [Reports].[dbo].[Eligible]
DECLARE #id int
DECLARE #LoopCount INT = 1
DECLARE #count int = #numrows
SELECT #id = [id] FROM [Reports].[dbo].[Eligible]
WHILE (#LoopCount <= #count)
BEGIN
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG,AlertDetails)
VALUES (52,52,#id,0,'Eligible',CURRENT_TIMESTAMP,'1900-01-01
00:00:00.000','N','')
SET #LoopCount = #LoopCount + 1
END
SELECT * FROM #TempTable
DROP TABLE #TempTable
I am assuming I have to tell it to loop through the values in the other table somehow but I am not positive if that is the right approach or if in general I am taking the long way around the bus.

Why are you using a loop? You can do this with an insert . . . select statement:
INSERT INTO #TempTable (CreatedByID, LastUpdatedByID, ID, AlertDE, Alert, StartDTTM, EndDTTM, IsInactiveFLAG, AlertDetails)
SELECT 52, 52, e.id, 0, 'Eligible', CURRENT_TIMESTAMP, '1900-01-01 00:00:00.000', 'N', ''
FROM [Reports].[dbo].[Eligible] e ;
See eg https://www.w3schools.com/sql/sql_insert_into_select.asp for more info.

GMR, I found a way to accomplish my need which is similar to yours. Hopefully this will help you too.
DECLARE
#LoopId int
,#TheOrderNumber varchar(20)
DECLARE #CheckThisItem TABLE
(
LoopId int not null identity(1,1)
,TheOrderNumber varchar(20) not null
)
INSERT #CheckThisItem
SELECT Order_Number AS TheOrderNumber
FROM [dbo].[Table_Storing_Order_Number] ORDER BY Order_Number ASC
SET #LoopId = ##rowcount
WHILE #LoopId > 0
BEGIN
SELECT #TheOrderNumber = TheOrderNumber
FROM #CheckThisItem
WHERE LoopId = #LoopId
-- Start inserting record pulled for while loop
INSERT [dbo].[The_Destination_Table]
SELECT TOP (1)
A, B, C, D
FROM [dbo].[Source_Table] ST
WHERE
ST.Order_Number = #TheOrderNumber
-- Set number to reduce loop counter
SET #LoopId = #LoopId - 1
END;

Related

Offset & Fetch Next will be ok to Use in a Loop?

I need to write a loop to pass data which are on a SQL temporary table to a stored procedure one by one. Is it OK to use the below approach? Does it cost lots of memory?
DECLARE #SomeData AS TABLE(
Id INT,
Name VARCHAR(MAX),
Age INT
)
INSERT INTO #SomeData
( Id, Name, Age )
VALUES ( 1, 'AAAAA', 10 ),
( 2, 'BBBBB', 12 ),
( 3, 'CCCCC', 13 ),
( 4, 'DDDDD', 14 ),
( 5, 'EEEEE', 15 );
DECLARE #iterator INT = 0
WHILE #iterator< (SELECT COUNT(Id) FROM #SomeData)
BEGIN
SELECT *
FROM #SomeData
ORDER BY Id
OFFSET #iterator ROWS
FETCH NEXT 1 ROWS ONLY
SET #iterator +=1
/*Execute a Stored Procedure*/
END
I think you don't need to (SELECT COUNT(Id) FROM #SomeData) again after while, if table SomeData is a big data it will slow. You can try like this:
DECLARE #iterator INT = 0
declare #n int = (SELECT COUNT(Id) FROM #SomeData)
WHILE #iterator< #n
BEGIN
SELECT *
FROM #SomeData
ORDER BY Id
OFFSET #iterator ROWS
FETCH NEXT 1 ROWS ONLY
SET #iterator +=1
/*Execute a Stored Procedure*/
END

dynamic alias in sql server

I want query field with different alias in stored procedure
select COUNT(EmpCode) as CountEmp+#para
result shoud be
CountEmp1
45
CountEmp2
54
CountEmp1
76
Query loop in c# code:
select COUNT(EmpCode) where something = #something as CountEmp+#para
Approach without dynamic SQL:
--I create temp table for demonstration
DECLARE #some_table TABLE (
Something int,
EmpCode INT
)
INSERT INTO #some_table (Something, EmpCode)
VALUES (1, 10),(1, 22),(1, 12),(2, 12),(2, 30),(3, 65),(3, 15),(3, 11),(3, 5)
--Declare parameter we want to search
DECLARE #param int = 1
--Query
--In cte we select what we need based on parameter
;WITH cte AS (
SELECT 'CountEmp'+CAST(#param as nvarchar(10)) as SomeThing,
CAST(COUNT(EmpCode) as nvarchar(10)) as EmpCodeCount,
ROW_NUMBER() OVER (ORDER BY SomeThing ) as rn
FROM #some_table
WHERE SomeThing = #param
GROUP BY SomeThing
)
--And here comes UNION
SELECT SomeThing as Result
FROM (
SELECT SomeThing,rn
FROM cte
UNION ALL
SELECT EmpCodeCount ,rn
FROM cte
) as t
ORDER BY rn, SomeThing DESC
Output:
Result
------------------
CountEmp1
3
(2 row(s) affected)
Please try to make use of below code. Its working fine with SQL Server 2012.
IF OBJECT_ID ('temp..#Mytable') IS NOT NULL
CREATE TABLE #Mytable (ID INT IDENTITY (1,1),EmpCode INT)
DECLARE #max int ,#count int
SET #max =0;
DECLARE #str varchar(10)
INSERT #Mytable
(EmpCode)
VALUES
(10),
(45),
(35),
(63),
(56),
(65)
SET #count = (SELECT COUNT (ID) FROM #Mytable )
WHILE #count > #max
BEGIN
SET #max = #max+1
SET #str = CONVERT(varchar(10),#max)
EXEC('SELECT EmpCode AS Empcode'+#str+ ' FROM #Mytable WHERE ID = '+#str)
END

SQL Server : loop through every row, add incremented value to column

I have just added a new column, Person_Id_Helper to MyTable. It is supposed to contain 1,2,3 etc, in the order the table is now sorted.
This is what I want to do:
DECLARE #i INT = 1, #NumberOfRows INT = SELECT COUNT(*) FROM MyTable
WHILE(#i <= #NumberOfRows)
BEGIN
-- Person_Id_Helper = #i
-- #i = #i + 1
END
How do I write this?
I think, that it might be the wrong idea to persist the sort oder within a column. But - for sure! - it is the wrong idea to do this in a while loop.
Read about row-based and set-based approaches. SQL demands for set-based thinking...
Look at this as an example how to do this (just paste it into an empty query window and execute, adapt to your needs):
DECLARE #tbl TABLE(SortDate DATE, Inx INT);
INSERT INTO #tbl VALUES({d'2016-01-20'},0)
,({d'2016-01-19'},0)
,({d'2016-01-14'},0)
,({d'2016-01-16'},0);
WITH cte AS
(
SELECT Inx,ROW_NUMBER() OVER(ORDER BY SortDate) AS RN
FROM #tbl
)
UPDATE cte SET Inx=RN;
SELECT * FROM #tbl;
I think this is what you want to achieve -
DECLARE #i INT = 0
UPDATE MyTable
SET
#i = Person_Id_Helper = #i + 1
Now check your column value.
Well we can not use ORDER BY clause in update statement. But to use it here is the updated query.
UPDATE t
SET Person_Id_Helper = rn.RowNum
FROM MyTable t
INNER JOIN (SELECT
ID
,ROW_NUMBER() OVER (ORDER BY ID) AS RowNum
FROM MyTable) rn
ON t.ID = rn.ID
#shungo: Thanks for point out.
Try like this,
DECLARE #tbl TABLE
(
datecolumn DATE,
Person_Id_Helper INT
);
INSERT INTO #tbl
VALUES ({d'2016-01-20'},
0),
({d'2016-01-19'},
0),
({d'2016-01-14'},
0),
({d'2016-01-16'},
0);
SELECT *
FROM #tbl;
UPDATE T
SET Person_Id_Helper = rn
FROM (SELECT Person_Id_Helper,
Row_number()
OVER(
ORDER BY datecolumn) AS rn
FROM #tbl) T
SELECT *
FROM #tbl;
Looping add increment the value using cursor in sqlserver
CREATE TABLE [dbo].[Table1](
[PID] [int] NULL,
[ProductDesc] [nvarchar](50) NULL,
[ProductCode] [nvarchar](10) NULL
) ON [PRIMARY]
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (1, N'Packet-Eye', N'P001', NULL)
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (2, N'Wiggy', N'W099 ', NULL)
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (3, N'Wimax-Lite', N'W001', NULL)
GO
INSERT [dbo].[Table1] ([PID], [ProductDesc], [ProductCode], [Person_Id_Helper]) VALUES (4, N'Wimax-Home', N'e W002 ', NULL)
GO
Declare #count int
DECLARE #PID int
set #count=0
DECLARE c1 CURSOR READ_ONLY
FOR
SELECT [PID] FROM [Table1]
OPEN c1
FETCH NEXT FROM c1 INTO #PID
WHILE ##FETCH_STATUS = 0
BEGIN
set #count=#count+1
update Table1 set Person_Id_Helper=#count where [PID]=#PID
FETCH NEXT FROM c1 INTO #PID END
CLOSE c1
DEALLOCATE c1
select * from Table1

Loop through a recordset and use the result to do another SQL select and return the results

I am completely new to stored procedure. This time, I need to create a stored procedure in MS SQL.
Let's say I have the following table.
Table name: ListOfProducts
--------------------------
SomeID, ProductID
34, 4
35, 8
35, 11
How do I pass in a SomeID. Use this SomeID to select a recordset from table, ListOfProducts. Then loop through this record set.
Let's say I pass in SomeID = 35.
So, the record set will return 2 records with SomeID 35. In the loop, I will get ProductID 8 and 11, which will be used to do another select from another table.
The stored procedure should return the results from the 2nd select.
How can I do this in MS SQL stored procedure?
Sorry, for this newbie question. Thanks for any help.
If you want looping through the records. You can do like:
--Container to Insert Id which are to be iterated
Declare #temp1 Table
(
tempId int
)
--Container to Insert records in the inner select for final output
Declare #FinalTable Table
(
Id int,
ProductId int
)
Insert into #temp1
Select Distinct SomeId From YourTable
-- Keep track of #temp1 record processing
Declare #Id int
While((Select Count(*) From #temp1)>0)
Begin
Set #Id=(Select Top 1 tempId From #temp1)
Insert Into #FinalTable
Select SomeId,ProductId From ListOfProducts Where Id=#Id
Delete #temp1 Where tempId=#Id
End
Select * From #FinalTable
There is probably no point in writing an explicit loop if you don't need to preform some action on the products that can't be done on the whole set. SQL Server can handle stuff like this much better on its own. I don't know what your tables look like, but you should try something that looks more like this.
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
SELECT
P.ProductId,
P.ProductName
FROM
Product P
JOIN
ListOfProducts LOP
ON LOP.ProductId = P.ProductId
WHERE
LOP.SomeId = #SomeID
END
I had to do something similar in order to extract hours from a select resultset start/end times and then create a new table iterating each hour.
DECLARE #tCalendar TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(MAX),
StartTime DATETIME,
EndTime DATETIME
)
INSERT INTO #tCalendar(RequestedFor,MeetingType,RoomName,StartTime,EndTime)
SELECT req as requestedfor
,meet as meetingtype
,room as rooms
,start as starttime
,end as endtime
--,u.datetime2 as endtime
FROM mytable
DECLARE #tCalendarHours TABLE
(
RequestedFor VARCHAR(50),
MeetingType VARCHAR(50),
RoomName VARCHAR(50),
Hour INT
)
DECLARE #StartHour INT,#EndHour INT, #StartTime DATETIME, #EndTime DATETIME
WHILE ((SELECT COUNT(*) FROM #tCalendar) > 0)
BEGIN
SET #StartTime = (SELECT TOP 1 StartTime FROM #tCalendar)
SET #EndTime = (SELECT TOP 1 EndTime FROM #tCalendar)
SET #StartHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,StartTime)) FROM #tCalendar)
SET #EndHour = (SELECT TOP 1 DATEPART(HOUR,DATEADD(HOUR,0,EndTime)) FROM #tCalendar)
WHILE #StartHour <= #EndHour
BEGIN
INSERT INTO #tCalendarHours
SELECT RequestedFor,MeetingType,RoomName,#StartHour FROM #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
SET #StartHour = #StartHour + 1
END
DELETE #tCalendar WHERE StartTime = #StartTime AND EndTime = #EndTime
END
Do something like this:
Declare #ID int
SET #ID = 35
SELECT
p.SomeID
,p.ProductID
FROM ListOfProducts p
WHERE p.SomeID = #ID
-----------------------
--Or if you have to join to get it
Declare #ID int
SET #ID = 35
SELECT
c.SomeID
,p.ProductID
,p.ProductName
FROM ListOfProducts p
INNER JOIN categories c on p.ProductID = c.SomeID
WHERE p.SomeID = #ID
You can use option with WHILE loop and BREAK/CONTINUE keywords
CREATE PROC dbo.yourProcName
#SomeID int
AS
BEGIN
IF OBJECT_ID('tempdb.dbo.#resultTable') IS NOT NULL DROP TABLE dbo.#resultTable
CREATE TABLE dbo.#resultTable
(Col1 int, Col2 int)
DECLARE #ProductID int = 0
WHILE(1=1)
BEGIN
SELECT #ProductID = MIN(ProductID)
FROM ListOfProducts
WHERE SomeID = #SomeID AND ProductID > #ProductID
IF #ProductID IS NULL
BREAK
ELSE
INSERT dbo.#resultTable
SELECT Col1, Col2
FROM dbo.yourSearchTable
WHERE ProductID = #ProductID
CONTINUE
END
SELECT *
FROM dbo.#resultTable
END
Demo on SQLFiddle

SQL: Retrieving Unique ID with Multiple Attributes

Ok, I had trouble describing this. I have:
material table (materialID, material, etc...)
ThicknessRange table (ThicknessRangeID, ThicknessRange)
MaterialThicknessRange table (MaterialID, ThicknessRangeID)
I am trying to retrieve all MaterialID's from the MaterialThicknessRange table that fit all required ThicknessRangeID's.
For example, any MaterialID with ThicknessRangeID 1 AND ThicknessRangeID 2, etc with a variable number of ThicknessRangeID's (selected from checkboxes by the user).
Thanks in advance.
Are you guaranteed to have only one entry in the MaterialThicknessRange table for a given Material/ThicknessRange combination?
SELECT MaterialID, COUNT(MaterialID) As NumMaterialThicknesses
FROM MaterialThicknessRange
WHERE ThicknessRangeID IN (1, 2)
GROUP BY MaterialID
HAVING COUNT(MaterialID) > 1
I'm using something like this
select MaterialID from MaterialThicknessRange MTR inner join
dbo.TransformCSVToTable('1,2,15') IDs on MTR.ThiknessRangeID = IDs.ID
where dbo.TransformCSVToTable is a user defined function to transform a csv string to a one column table. Bellow is one sample of such function
ALTER FUNCTION [dbo].[fn_IntegerParameterListFromString]
(
#IntegerParameterList varchar(max)
)
RETURNS #result TABLE (IntegerID int)
AS
begin
declare #temp table (IntegerID int)
declare #s varchar(max), #s1 varchar(10)
declare #len int
set #len =len(#IntegerParameterList)
set #s = #IntegerParameterList
if (right(#s,1)<>',') set #s = #s +','
while #s<>''
begin
set #s1 = substring(#s,1,charindex(',',#s)-1)
if (isnumeric(#s1)= 1)
insert #result (IntegerID) Values ( Cast(#s1 as int))
if (CHARINDEX(',',#s)>0)
begin
set #s = substring (#s, charindex(',',#s)+1, #Len)
end
else
begin
if isnumeric(#s) = 1
insert #result (IntegerID) Values ( Cast(#s as int))
set #s = ''
end
end
return
end