I am trying to define multiple count values for a counter and corresponding value. Here is my code:
DECLARE #RequestDate AS DATE = '2017-04-20'
;
DECLARE #POCounter INT;
DECLARE #POMax INT;
DECLARE #NewDate DATE;
SET #POCounter = 0;
SET #POMax =
(
SELECT
CUSTOMERPONUMBER,
(
SELECT
COUNT(CUSTOMERPONUMBER)
FROM DailyOpenOrders$
WHERE
RequestDate < #RequestDate
)
FROM DailyOpenOrders$
WHERE
RequestDate < #RequestDate
GROUP BY
CUSTOMERPONUMBER
)
The #POMax counter is to help me update the date that many times for a specific customerPO. I intend to increase the POCounter in a loop until it reaches the #POmax counter for each customerPOnumber.
Am i doing this wrong? can someone help?
#POMax is a scalar variable and can only hold one value at a time.
If you want to hold a collection of values, a table variable is a good tool for that:
DECLARE #MyTable TABLE
(
ID int PRIMARY KEY IDENTITY(1,1),
CustomerNumber varchar(50),
[TheCount] int
)
INSERT INTO #MyTable(CustomerNumber, [TheCount])
SELECT CustomerNumber, COUNT(*)
FROM SomeTable
GROUP BY CustomerNumber
Now you can loop over #MyTable, and for each CustomerNumber, loop from 1 to TheCount...
DECLARE #MyID int
SET #MyID = (SELECT MIN(ID) FROM #MyTable)
WHILE #MyID is not null
BEGIN
SELECT * FROM #MyTable WHERE ID = #MyID
SET #MyID = (SELECT MIN(ID) FROM #MyTable WHERE #MyID < ID)
END
Related
I need to be able to SELECT a specific row because SET only holds one row.
On line 5, I have to declare #json so that OPENJSON can work.
And that's why i need the RowNo at this point in the query. However, at this point, RowNo is not defined.
How would i go about fixing this problem? It seems that it doesn't matter how i spin it, something is always gonna be undefined. How would i point to a specific row on line 5 as desired?
DECLARE #loopCounter INT = 0;
WHILE #loopCounter < (SELECT count(Id) FROM ProcessEventMessages)
BEGIN
PRINT 'Changing...';
DECLARE #json NVARCHAR(MAX) = (SELECT Data FROM ProcessEventMessages WHERE RowNo = #loopCounter) -- here
SELECT * FROM OPENJSON(#json)
WITH (
message varchar(200) '$.message',
machineId varchar(200) '$.machineId',
machineName int '$.machineName',
ipAddress varchar(200) '$.ipAddress',
LocalTime datetime2(7) '$.time'
) AS ChangeTime;
;WITH CTE AS(
SELECT *,ROW_NUMBER() OVER(Order by Id ASC) AS RowNo
FROM ProcessEventMessages
)
UPDATE CTE
SET Data = JSON_MODIFY(#json,'$.time', FORMAT(DATEADD(hour,-2,JSON_VALUE(#json,'$.time')),'yyyy-MM-ddTHH:mm:ss.fff'))
WHERE RowNo = #loopCounter
SET #loopCounter = #loopCounter + 1;
END;
PRINT 'Done';
GO
You can use CROSS APPLY instead of a loop. Try:
WITH CTE AS (
SELECT
LocalTime
, Data
FROM dbo.ProcessEventMessages
CROSS APPLY OPENJSON(Data)
WITH (
LocalTime datetime2(7) '$.time'
) AS ChangeTime
)
UPDATE CTE
SET Data = JSON_MODIFY(Data,'$.time', FORMAT(DATEADD(hour,-2,LocalTime),'yyyy-MM-ddTHH:mm:ss.fff'));
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;
I have this code:
DECLARE #TotalPayment DECIMAL(18,4)
DECLARE #GetTotalPaymentAmount AS TABLE
(
Amount DECIMAL(18,4),
CurrencyId CHAR(3)
)
INSERT INTO #GetTotalPaymentAmount
SELECT SUM(Amount), CurrencyId
FROM [dbo].[fn_DepositWithdrawReport]()
WHERE OperationTypeId = 2
GROUP BY CurrencyId
SET #TotalPayment = (SELECT Amount FROM #GetTotalPaymentAmount)
I am getting this error
Subquery returned more than 1 value.
So yes, I know that the issue in SET logic because #GetTotalPayment returning more than one row. If I am using for example TOP 1, it is working great, but I need all values of that table. How could I get all values and assign them to local variables from that table?
I am getting table like this
A 'C
---'---
10 'USD
20 'EURO
'
and I need to retrieve all of these values.
Please note that I do not know how many rows will be returned from temp table and saying just declare second variable won't work. The whole point of this would be eventually pass that variables to function as input parameter.
Here, I modified your code slightly. Should work :)
DECLARE #TotalPayment DECIMAL(18,4)
DECLARE #GetTotalPaymentAmount AS TABLE
(
Id int identity(1,1),--added Id column
Amount DECIMAL(18,4),
CurrencyId CHAR(3)
)
INSERT INTO #GetTotalPaymentAmount
SELECT SUM(Amount),CurrencyId
FROM [dbo].[fn_DepositWithdrawReport]()
WHERE OperationTypeId = 2
GROUP BY CurrencyId
declare #i int, #cnt int
set #i = 1
select #cnt = COUNT(*) from #GetTotalPaymentAmount
while #i <= #cnt
begin
select #TotalPayment = Amount from #GetTotalPaymentAmount where Id = #i
--do stuff with retrieved value
#i += 1
end
#So_Op
If you want the data to use in a SCALAR function then just do this
SELECT
G.Amount
,dbo.FN_ScalarFunction(G.Amount)
FROM
#GetTotalPaymentAmount G
If it's a TABLE Function then this works
SELECT
G.Amount
,F.ReturnValue
FROM
#GetTotalPaymentAmount G
CROSS APPLY
dbo.FN_TableFunction(G.Amount) F
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
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