How to store result of a select statement into a variable? - sql

I tried with the below code:
DECLARE #rec_count int
Set #rec_count= select 1
but it shows error
"Incorrect syntax near Select".

Either:
set #rec_count = (select 1)
or
select #rec_count = 1
An example assigning the count from a table to variable:
set #rec_count = (select COUNT(*) from master..spt_values)
select #rec_count = COUNT(*) from master..spt_values
However, if you just want to assign a value to a variable you don't need any select statement:
set #rec_count = 1
or
declare #rec_count int = 1

To store the result of a select statement into a variable, see below
DECLARE #rec_count INT
SELECT #rec_count = 1
We can get more than one value from select statement as below
DECLARE #rec_count INT
DECLARE #date DATETIME
SELECT #rec_count = 1, #date = GETDATE()

If you're trying to get a record count, which looks like what you're trying to do, you can do this:
declare #rec_count int
select #rec_count = count(1) from [your_table] -- where some condition is met
Note: Use count(1) instead of count(*) as it's quicker to simply select a single column than all when getting a count.
Or if this count is the result of some inserts/updates/selects/deletes, you can use the ##ROWCOUNT, which:
Returns the number of rows affected by the last statement.
So if for example you are performing an update or select and want to know how many rows were affected, it will automatically be stored by SQL Server in the ##ROWCOUNT.
declare #rec_count int
-- some table change
update your_table
set col1 = 1
where col1 = 0
set #rec_count = ##ROWCOUNT
-- select ##ROWCOUNT <-- this would return the number of rows updated

DECLARE #rec_count int;
Set #rec_count = 1;

Related

SQL Grouping with condition

I want to sum rows in table. The algorithm is rather simple in theory but hard (at least for me) when I need to build a query.
Generally, I want to sum "values" of a "sub-group". Sub-group is defined as a range of elements starting with first row where type=0 and finishing with last row where type=1. the sub-group should contain only one (first) row with type=0.
The sample below presents correct (left) and incorrect (right) behavior.
I tried several approaches including grouping and partitioning. Unfortunately w/o any success. Anybody had similar problem?
I used MS SQL Server (so T-SQL 'magic' is allowed)
EDIT:
The results I want:
"ab",6
"cdef",20
"ghi",10
"kl",8
You can identify the groups by doing a cumulative sum of zeros. Then use aggregation or window functions.
Note that SQL tables represent unordered sets, so you need a column to specify the ordering. The code below assumes that this column is id.
select min(id), max(id), sum(value)
from (select t.*,
sum(case when type = 0 then 1 else 0 end) over (order by id) as grp
from t
) t
group by grp
order by min(id);
You can use window function with cumulative approach :
select t.*, sum(value) over (partition by grp)
from (select t.*, sum(case when type = 0 then 1 else 0 end) over (order by id) as grp
from table t
) t
where grp > 0;
Solution with a cursor and output-table.
As Gordon wrote it is not defined how the set will be ordered, so ID is also used here.
declare #output as table (
ID_sum nvarchar(max)
,value_sum int
)
DECLARE #ID as nvarchar(1)
,#value as int
,#type as int
,#ID_sum as nvarchar(max)
,#value_sum as int
,#last_type as int
DECLARE group_cursor CURSOR FOR
SELECT [ID],[value],[type]
FROM [t]
ORDER BY ID
OPEN group_cursor
FETCH NEXT FROM group_cursor
INTO #ID, #value,#type
WHILE ##FETCH_STATUS = 0
BEGIN
if (#last_type is null and #type = 0)
begin
set #ID_sum = #ID
set #value_sum = #value
end
if (#last_type in(0,1) and #type = 1)
begin
set #ID_sum += #ID
set #value_sum += #value
end
if (#last_type = 1 and #type = 0)
begin
insert into #output values (#ID_sum, #value_sum)
set #ID_sum = #ID
set #value_sum = #value
end
if (#last_type = 0 and #type = 0)
begin
set #ID_sum = #ID
set #value_sum = #value
end
set #last_type = #type
FETCH NEXT FROM group_cursor
INTO #ID, #value,#type
END
CLOSE group_cursor;
DEALLOCATE group_cursor;
if (#last_type = 1)
begin
insert into #output values (#ID_sum, #value_sum)
end
select *
from #output

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

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

Issues with SQL Max function: "Incorrect syntax new the keyword 'SELECT' "

I'm trying to write a stored procedure to return the maximum value of a column + 1 but for some reason it doesn't want to work.
DECLARE #ID int;
SET #ID = SELECT MAX(ID) + 1 FROM tbl;
I can't for the life of me see what is wrong.
It gives me the error of:
incorrect syntax new the keyword 'SELECT'
No need for SET. Select value directly:
DECLARE #ID int;
SELECT #ID = MAX(ID) + 1 FROM tbl;
Use parentheses ( ... ):
DECLARE #ID int;
SET #ID = (SELECT MAX(ID) + 1 FROM tbl);
or SELECT as suggested by Giorgi. SET is the ANSI standard way of assigning values to variables, SELECT is not. Apart from that using SELECT to assign values to variables is fine, it allows even multiple assignments with one SELECT.
But in general your query seems to be a race condition. Use an IDENTITY column if you want to autoincrement a value. Auto increment primary key in SQL Server Management Studio 2012
You need to consider a scenario when there is no value in the table and MAX returns NULL.
DECLARE #ID int;
SELECT #ID = ISNULL(MAX(ID) , 0) + 1 FROM tbl;
Other adding 1 to null will always yield null.
DECLARE #ID int;
SET #ID = (SELECT MAX(ID) + 1 FROM tbl);
parentheses operator ()
for more information
https://msdn.microsoft.com/en-us/library/ms190276.aspx

Is there any way to select records if top clause parameter is null?

Is there any way to select records if top clause parameter is null?
DECLARE #count FLOAT = 0;
Select #count = count from tblDetails
SELECT TOP(#count) from tblCompany
If #count var is null than i want to select all records from tblCompany.
DECLARE #count FLOAT = 0;
Select #count = count(1) from tblDetails
IF #count > 0
BEGIN
SELECT TOP(#intRecords) * from tblCompany
END
ELSE
BEGIN
SELECT * FROM tblCompany
END
If you do not want to write the query twice - although only one will get executed, you can try this:
DECLARE #count FLOAT = 0;
Select #count = count(1) from tblDetails
IF #count = 0
BEGIN
SET #intRecords = 100000 -- Or some number larger than the possible count
END
SELECT TOP(#intRecords) * from tblCompany
When facing situations like this one, I love using SQL Rank.
In the query below I assumed you have an ID column, but you can replace it with any other column for choosing the criteria for what would be considered to be the top columns:
DECLARE #count FLOAT = 0;
Select #count = count(*) from tblDetails
SELECT * FROM
(
SELECT
RANK () OVER
( ORDER BY ID ) 'Rank', -- <-- Assuming you have an ID column, replace with any other criteria for what will be considered as top...
*
FROM tblCompany
) tmp
WHERE (#count IS NULL) OR tmp.Rank <= #count
I think this would work:
DECLARE #count AS INT ;
Set #count = (Select count(*) from tblDetails);
SELECT TOP(ISNULL(#count,5)) * from tblCompany

top count for a SQL query

I want to have a variable for selecting top rows. I can select top rows based on a variable. However I want to select all rows if the variable is not supplied.
Currently I'm using this query:
DECLARE #TOPCOUNT int;
SET #TOPCOUNT=10;
SELECT TOP(#TOPCOUNT) * FROM TABLE1
Update:
The original query is very lengthy and complex, so I don't to rewrite the entire query without top count in else clause.
I don't want to use dynamic query because of its repercussions.
Something like this:
DECLARE #TOPCOUNT int;
--SET #TOPCOUNT=10;
IF #TOPCOUNT IS NULL
SELECT * FROM TABLE1
ELSE
SELECT TOP(#TOPCOUNT) * FROM TABLE1
Added after above UPDATE - if this is a parameter of a Stored Procedure then just provide a default for #TOPCOUNT:
#TOPCOUNT INT = 2147483647 --max size of INT
Something like this will help. Just init your #TOPCOUNT with -1 if you want all rows.
IF #TOPCOUNT = -1 BEGIN
SELECT * FROM TABLE1
END
ELSE BEGIN
SELECT TOP(#TOPCOUNT) * FROM TABLE1
END
IF #TOPCOUNT IS NULL SET #TOPCOUNT=2147483647