How to retrieve values from TempTable and set that values in local variables - sql

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

Related

Inserting data with SQL

Similar questions have already appeard here, but it seems like I'm doing the same as in other instructions, but it doesn't work. So I have
Declare #Counter Int
Set #Counter = 1
while #Counter <= 1000
Begin
insert into Kiso_task_table ([Numbers],[Square_root])
values ( #Counter, Sqrt(#Counter));
Set #Counter = #Counter + 1;
CONTINUE;
End
SELECT TOP (1000) [Numbers],[Square_root]
FROM [Kiso_task].[dbo].[Kiso_task_table]
and it should give me Numbers from 1 to 1000 and their square roots, respectively - instead it produces "1" all the times? Do you know what is wrong?
Your error is in the type of variable to convert the square root, it must be of the 'float' type
CREATE TABLE #Kiso_task_table
(
[Numbers] INT,
[Square_root] FLOAT,
);
GO
DECLARE #Counter INT
SET #Counter = 1
WHILE #Counter <= 1000
BEGIN
INSERT INTO #Kiso_task_table ([Numbers],[Square_root]) VALUES ( #Counter, Sqrt(#Counter));
SET #Counter = #Counter + 1
CONTINUE
END
SELECT TOP (1000) [Numbers],[Square_root]
FROM #Kiso_task_table
SQRT (Transact-SQL)
Your approach is procedural thinking. Try to start thinking set-based. That means: No CURSOR, no WHILE, no loopings, no do this and then this and finally this. Let the engine know, what you want to get back and let the engine decide how to do this.
DECLARE #mockupTarget TABLE(Number INT, Square_root DECIMAL(12,8));
WITH TallyOnTheFly(Number) AS
(
SELECT TOP 1000 ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) FROM master..spt_values
)
INSERT INTO #mockupTarget(Number,Square_root)
SELECT Number,SQRT(Number)
FROM TallyOnTheFly;
SELECT * FROM #mockupTarget ORDER BY Number;
The tally-cte will create a volatile set of 1000 numbers. This is inserted in one single statement.
Btw
I tested your code against my mockup table and it was working just fine...

declaring multiple columns in a count value

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

How to get query result with stored procedure (convert item quantity from one table into my unit defined in second table)

I have two MSSQL2008 tables like this:
I have problem on the unit conversion logic.
The result I expect like this :
1589 cigar = 1ball, 5slop, 8box, 2pcs
52 pen = 2box, 12pcs
Basically I'm trying to take number (qty) from one table and to convert (split) him into the units which I defined in other table!
Note : Both table are allowed to add new row and new data (dinamic)
How can I get these results through a SQL stored procedure?
i totally misunderstand the question lest time so previous answer is removed (you can see it in edit but it's not relevant for this question)... However i come up with solution that may solve your problem...
NOTE: one little think about this solution, if you enter the value in second table like this
+--------+-------+
| Item | qty |
+--------+-------+
| 'cigar'| 596 |
+--------+-------+
result for this column will be
598cigar = 0ball, 5slop, 8box, 0pcs
note that there is a ball and pcs is there even if their value is 0, that probably can be fix if you don't want to show that value but I let you to play with it...
So let's back to solution and code. Solution have two stored procedures first one is the main and that one is the one you execute. I call it sp_MainProcedureConvertMe. Here is a code for that procedure:
CREATE PROCEDURE sp_MainProcedureConvertMe
AS
DECLARE #srcTable TABLE(srcId INT IDENTITY(1, 1), srcItem VARCHAR(50), srcQty INT)
DECLARE #xTable TABLE(xId INT IDENTITY(1, 1), xVal1 VARCHAR(1000), xVal2 VARCHAR(1000))
DECLARE #maxId INT
DECLARE #start INT = 1
DECLARE #sItem VARCHAR(50)
DECLARE #sQty INT
DECLARE #val1 VARCHAR(1000)
DECLARE #val2 VARCHAR(1000)
INSERT INTO #srcTable (srcItem, srcQty)
SELECT item, qty
FROM t2
SELECT #maxId = (SELECT MAX(srcId) FROM #srcTable)
WHILE #start <= #maxId
BEGIN
SELECT #sItem = (SELECT srcItem FROM #srcTable WHERE srcId = #start)
SELECT #sQty = (SELECT srcQty FROM #srcTable WHERE srcId = #start)
SELECT #val1 = (CAST(#sQty AS VARCHAR) + #sItem)
EXECUTE sp_ConvertMeIntoUnit #sItem, #sQty, #val2 OUTPUT
INSERT INTO #xTable (xVal1, xVal2)
VALUES (#val1, #val2)
SELECT #start = (#start + 1)
CONTINUE
END
SELECT xVal1 + ' = ' + xVal2 FROM #xTable
GO
This stored procedure have two variables as table #srcTable is basically your second table but instead of using id of your table it's create new srcId which goes from 1 to some number and it's auto_increment it's done because of while loop to avoid any problems when there is some deleted values etc. so we wanna be sure that there wont be any skipped number or something like that.
There is few more variables some of them is used to make while loop work other one is to store data. I think it's not hard to figure out from code what are they used for...
While loop iterate throughout all rows from #srcTable take values processing them and insert them into #xTable which basically hold result.
In while loop we execute second stored procedure which have a task to calculate how many unit of something is there in specific number of item. I call her sp_ConvertMeIntoUnit and here is a code for her:
CREATE PROCEDURE sp_ConvertMeIntoUnit
#inItemName VARCHAR(50),
#inQty INT,
#myResult VARCHAR(5000) OUT
AS
DECLARE #rTable TABLE(rId INT IDENTITY(1, 1), rUnit VARCHAR(50), rQty INT)
DECLARE #yTable TABLE(yId INT IDENTITY(1, 1), yVal INT, yRest INT)
DECLARE #maxId INT
DECLARE #start INT = 1
DECLARE #quentity INT = #inQty
DECLARE #divider INT
DECLARE #quant INT
DECLARE #rest INT
DECLARE #result VARCHAR(5000)
INSERT INTO #rTable(rUnit, rQty)
SELECT unit, qty
FROM t1
WHERE item = #inItemName
ORDER BY qty DESC
SELECT #maxId = (SELECT MAX(rId) FROM #rTable)
WHILE #start <= #maxId
BEGIN
SELECT #divider = (SELECT rQty FROM #rTable WHERE rId = #start)
SELECT #quant = (#quentity / #divider)
SELECT #rest = (#quentity % #divider)
INSERT INTO #yTable(yVal, yRest)
VALUES (#quant, #rest)
SELECT #quentity = #rest
SELECT #start = (#start + 1)
CONTINUE
END
SELECT #result = COALESCE(#result + ', ', '') + CAST(y.yVal AS VARCHAR) + r.rUnit FROM #rTable AS r INNER JOIN #yTable AS y ON r.rId = y.yId
SELECT #myResult = #result
GO
This procedure contain three parametars it's take two parameters from the first one and one is returned as result (OUTPUT). In parameters are Item and Quantity.
There are also two variables as table #rTable we stored values as #rId which is auto increment and always will go from 1 to some number no matter what is there Id's in the first table. Other two values are inserted there from the first table based on #inItemName parameter which is sanded from first procedure... From the your first table we use unit and quantity and stored them with rId into table #rTable ordered by Qty from biggest number to lowest. This is a part of code for that
INSERT INTO #rTable(rUnit, rQty)
SELECT unit, qty
FROM t1
WHERE item = #inItemName
ORDER BY qty DESC
Then we go into while loop where we do some maths. Basically we store into variable #divider values from #rTable. In the first iteration we take the biggest value calculate how many times it's contain into the number (second parameter we pass from first procedure is qty from the yours second table) and store it into #quant than we also calculate modulo and store it into variable #rest. This line
SELECT #rest = (#quentity % #divider)
After that we insert our values into #yTable. Before we and with iteration in while loop we assign #quentity variable value of #rest value because we need to work just with the remainder not with whole quantity any more. In second iteration we take next (the second greatest number in our #rTable) number and procedure repeat itself...
When while loop finish we create a string. This line here:
SELECT #result = COALESCE(#result + ', ', '') + CAST(y.yVal AS VARCHAR) + r.rUnit FROM #rTable AS r INNER JOIN #yTable AS y ON r.rId = y.yId
This is the line you want to change if you want to exclude result with 0 (i talk about them at the beginning of answer)...
And at the end we store result into output variable #myResult...
Result of this stored procedure will return string like this:
+--------------------------+
| 1ball, 5slop, 8box, 2pcs |
+--------------------------+
Hope I didn't miss anything important. Basically only think you should change here is the name of the table and their columns (if they are different) in first stored procedure instead t2 here
INSERT INTO...
SELECT item, qty
FROM t2
And in second one instead of t1 (and column if needed) here..
INSERT INTO...
SELECT unit, qty
FROM t1
WHERE item = #inItemName
ORDER BY qty DESC
Hope i help a little or give you an idea how this can be solved...
GL!
You seem to want string aggregation – something that does not have a simple instruction in Transact-SQL and is usually implemented using a correlated FOR XML subquery.
You have not provided names for your tables. For the purpose of the following example, the first table is called ItemDetails and the second one, Items:
SELECT
i.item,
i.qty,
details = (
SELECT
', ' + CAST(d.qty AS varchar(10)) + d.unit
FROM
dbo.ItemDetails AS d
WHERE
d.item = i.item
FOR XML
PATH (''), TYPE
).value('substring(./text()[1], 3)', 'nvarchar(max)')
FROM
dbo.Items AS i
;
For the input provided in the question, the above query would return the following output:
item qty details
----- ----------- ------------------------------
cigar 1598 1pcs, 1000ball, 12box, 100slop
pen 52 1pcs, 20box
You can further arrange the data into strings as per your requirement. I would recommend you do it in the calling application and use SQL only as your data source. However, if you must, you can do the concatenation in SQL as well.
Note that the above query assumes that the same unit does not appear more than once per item in ItemDetails. If it does and you want to aggregate qty values per unit before producing the detail line, you will need to change the query a little:
SELECT
i.item,
i.qty,
details = (
SELECT
', ' + CAST(SUM(d.qty) AS varchar(10)) + d.unit
FROM
dbo.ItemDetails AS d
WHERE
d.item = i.item
GROUP BY
d.unit
FOR XML
PATH (''), TYPE
).value('substring(./text()[1], 3)', 'nvarchar(max)')
FROM
dbo.Items AS i
;

Using a variable as the column name

My question here is how do I use a variable to be a column name in a select statement. I have created the variable #B to be a column name that is BGNDATE1 through BGNDATE12. Rather than have 12 select statements I created a while loop. The column name is basically BGNDATE + the incremented integer.
The error I am getting is:
Conversion failed when converting the varchar value 'BGNDATE1' to data type int.
USE X --this is the database
DECLARE #DATES TABLE (ROWID INT, FISCDATES INT)
DECLARE #FY INT = 2012
DECLARE #I INT
DECLARE #IV VARCHAR(2)
DECLARE #B VARCHAR(9)
SELECT #FY AS FY
SET #I = 1
WHILE #I <= 12
BEGIN
SET #IV = #I
SET #B = 'BGNDATE' + #IV
INSERT INTO #DATES (ROWID)
SELECT #I
MERGE INTO #DATES AS T
USING (
--This is where the error is with regards to the variable #B
SELECT #B AS FISCDATES FROM DBO.Y -- Y is the table in the database
WHERE FSCYEAR = #FY) AS S
ON T.ROWID = #I
WHEN MATCHED
THEN UPDATE
SET T.FISCDATES = S.FISCDATES;
SET #I = #I + 1
END
SELECT * FROM #DATES
You can't use a variable as a column name (unless you create the entire query dynamically), but you can use a variable to select from different columns:
...
SELECT
CASE #IV
WHEN 1 THEN BGNDATE1
WHEN 2 THEN BGNDATE2
WHEN 3 THEN BGNDATE3
WHEN 4 THEN BGNDATE4
WHEN 5 THEN BGNDATE5
WHEN 6 THEN BGNDATE6
WHEN 7 THEN BGNDATE7
WHEN 8 THEN BGNDATE8
WHEN 9 THEN BGNDATE9
WHEN 10 THEN BGNDATE10
WHEN 11 THEN BGNDATE11
WHEN 12 THEN BGNDATE12
END AS FISCDATES FROM DBO.Y
...
When you select #B that won't work because #B is not a column name, it is a variable.
It would be best to denormalize the table so instead of having 12 columns named BGNDATE 1 through 12 you had another table to join to.
If you can't do that, do it with dynamic sql:
exec('MERGE INTO #DATES AS T
USING (
SELECT ' + #B + ' AS FISCDATES FROM DBO.Y
WHERE FSCYEAR = #FY) AS S
ON T.ROWID = #I
WHEN MATCHED
THEN UPDATE
SET T.FISCDATES = S.FISCDATES;')

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