Declare and assign result from stored procedure in one line - sql-server

Is it possible to declare and assign the result from an sp in one statement?
If we can do,
DECLARE #lastid INTEGER = (SELECT MAX([Id]) FROM [ADVWKS].[dbo].[Account]);
why cant we do the below one?
DECLARE #lastaccid INTEGER = (EXEC sp_GetGlobalVarVal 'LAST_ACCID');
So far you need one statement to declare the variable and one to execute the procedure and assign the variable as return, output, cursor etc. Can we do it in a single statement??

You cannot do the below because it is often the case that the return type for the stored procedure is a table. It would either execute, and run DML statements which wont return anything, or it would return data set. Now what you can do is to build a scalar value function instead of stored procedure and select from that. https://learn.microsoft.com/en-us/sql/t-sql/statements/create-function-transact-sql?view=sql-server-2017
Another possibility is using: https://learn.microsoft.com/en-us/sql/relational-databases/stored-procedures/return-data-from-a-stored-procedure?view=sql-server-2017#returning-data-using-a-return-code, but conceptually per article, this is only used for Return Codes, not really for the variable assignment or populating variables for different types, and do not forget, there is only values between 0 - 4.

Use an OUTPUT parameter instead. This is very simplified, however:
CREATE PROC TEST_SP #I int, #O int OUTPUT AS
SET #O = #I *5;
GO
DECLARE #Var int;
EXEC TEST_SP 1,#Var OUTPUT;
SELECT #Var;
GO
--CLEAN UP
DROP PROC TEST_SP;

You can use OUTPUT Parameters:
This is an example SP where the second variable (#Param_2) is defined as output Parameter
CREATE PROCEDURE [dbo].[MySP]
(
#Param_1 int,
#Param_2 int output
)
AS
BEGIN
SET NOCOUNT ON;
SET #Param_2 = 10 * #Param_1;
END
Now you can call the SP like this:
DECLARE #Value_1 INT = 42;
DECLARE #RetVal INT = 0;
SELECT #RetVal;
EXEC [dbo].[MySP] #Value_1, #Param_2 = #RetVal OUTPUT;
SELECT #RetVal;
The frist time you select #RetVal the value will still be 0. After the execution of the SP, #RetVal will be 420 (10 * 42 calcualted inside the SP):
-----------
0
(1 row affected)
-----------
420
(1 row affected)
TLDR: No :)

Related

When exactly do we use stored procedures with output parameters?

When exactly do we use stored procedures with output parameters and when do we use stored procedures without parameters?
I base my question on an example:
Stored procedure with output parameter
CREATE PROCEDURE uspGetContactsCountByCity
#City nvarchar(60),
#ContactsCount int OUT
AS
BEGIN
SELECT #ContactsCount = COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing
DECLARE #ContactsTotal INT
EXEC uspGetContactsCountByCity #ContactsCount = #ContactsTotal OUT, #city = 'Berlin'
SELECT #ContactsTotal
Results: 2
Stored procedure without output parameter
CREATE PROCEDURE uspGetContactsCountByCity2
#City nvarchar(60)
AS
BEGIN
SELECT COUNT(ContactID)
FROM Contacts
WHERE City = #City
END
Stored procedure executing:
EXEC uspGetContactsCountByCity2 #city = 'Berlin'
Results: 2
Both procedures return the same result, in same form, so what's the difference?
Basically, the result you're seeing is actually the result of your SELECT at the end of the procedure, which is doing the same thing.
Please take a look at this documentation:
If you specify the OUTPUT keyword for a parameter in the procedure definition, the stored procedure can return the current value of the parameter to the calling program when the stored procedure exits. To save the value of the parameter in a variable that can be used in the calling program, the calling program must use the OUTPUT keyword when executing the stored procedure.
So basically if you would like your stored procedure to just return just a value instead of a data set, you could use the output parameter. For example, let's take the procedures you have given as an example. They both do the same thing, this is why you got the same result. But what about changing a little bit in the first procedure that has the output parameter.
Here's an example:
create table OutputParameter (
ParaName varchar(100)
)
insert into OutputParameter values ('one'), ('two'),('three'),('one')
CREATE PROCEDURE AllDataAndCountWhereOne
#name nvarchar(60),
#count int OUT
as
Begin
SELECT #count = COUNT(*) from OutputParameter
Where ParaName = #name
select Distinct(ParaName) from OutputParameter
End
Declare #TotalCount int
Exec AllDataAndCountWhereOne #count = #TotalCount OUT, #name = 'One'
Select #TotalCount
With this example, you are getting all the distinct stored data in the table, plus getting the count of a given name.
ParaName
--------------------
one
three
two
(3 row(s) affected)
-----------
2
(1 row(s) affected)
This is one way of using the output parameter. You got both the distinct data and the count you wanted without doing extra query after getting the initial data set.
At the end, to answer your question:
Both procedures gives us the same result, in same form, so what's the difference?
You didn't make a difference in your own results, this is why you didn't really notice the difference.
Other Examples:
You could use the OUT parameter in other kinds of procedures. Let's assume that your stored procedure doesn't return anything, it's more like a command to the DB, but you still want a kind of message back, or more specifically a value. Take these two examples:
CREATE PROCEDURE InsertDbAndGetLastInsertedId
--This procedure will insert your name in the database, and return as output parameter the last inserted ID.
#name nvarchar(60),
#LastId int OUT
as
Begin
insert into OutputParameterWithId values (#name);
SELECT #LastId = SCOPE_IDENTITY()
End
or:
CREATE PROCEDURE InsertIntoDbUnlessSomeLogicFails
--This procedure will only insert into the db if name does exist, but there's no more than 5 of it
#name nvarchar(60),
#ErrorMessage varchar(100) OUT
as
Begin
set #ErrorMessage = ''
if ((select count(*) from OutputParameterWithId) = 0)
begin
set #ErrorMessage = 'Name Does Not Exist'
return
end
if ((select count(*) from OutputParameterWithId) = 5)
begin
set #ErrorMessage = 'Already have five'
return
end
insert into OutputParameterWithId values (#name);
End
These are just dummy examples, but just to make the idea more clear.
An example, based on yours would be if you introduced paging to the query.
So the result set is constrained to 10 items, and you use a total count out parameter to drive paging on a grid on screen.
Answer from ozz regarding paging does not make sense because there is no input param that implements a contraint on the number of records returned.
However, to answer the question... the results returned by these stored procedures are not the same. The first returns the record count of contacts in given city in the out param ContactsCount. While the count may also be recieved in the second implement through examining the reader.Rows.Count, the actual records are also made a available. In the first, no records are returned - only the count.

calling SP from within another SP gives different result

I have a simple stored procedure that fetches an int from a table and updates the table.
This is the complete stored procedure
create procedure spGetNewVMacsBatchNumber as
begin
set nocount on
declare #LastUsedVMacsBatchNumber int
update tblSettings with (TABLOCK)
set LastUsedVMacsBatchNumber = isnull(LastUsedVMacsBatchNumber, 0) + 1,
#LastUsedVMacsBatchNumber = isnull(LastUsedVMacsBatchNumber, 0) + 1
select #LastUsedVMacsBatchNumber
end;
When I run this from SSMS it does what I expect from it, return the number + 1 and update the table.
I call it in SSMS like this :
declare #BatchNumber int
exec #BatchNumber = spGetNewVMacsBatchNumber
But when I call it from within another stored procedure it does not returns the value I expect, but always returns zero. The call in the other stored procedure is exact the same as above.
How can I call this stored procedure from another stored procedure and still get the value I expect ?
The idea for spGetNewVMacsBatchNumber is to retrieve the current value + 1 and to make sure it does not returns a wrong value when 2 processes run it at the same time.
Maybe there is a better way of doing that then my approach ?
You should actually use output parameters for your procedure.
alter procedure spGetNewVMacsBatchNumber #ReturnVal int output as
begin
set nocount on
declare #LastUsedVMacsBatchNumber int
update tblSettings with (TABLOCK)
set LastUsedVMacsBatchNumber = isnull(LastUsedVMacsBatchNumber, 0) + 1,
#LastUsedVMacsBatchNumber = isnull(LastUsedVMacsBatchNumber, 0) + 1
select #ReturnVal = #LastUsedVMacsBatchNumber
end;
And then call it like this:
declare #BatchNumber int
exec spGetNewVMacsBatchNumber #ReturnVal= #BatchNumber output;
select #BatchNumber
You are getting the return status of the spGetNewVMacsBatchNumber stored procedure like that, not the actual "return value" from the stored proc.

T-SQL stored procedure - Detecting if a parameter is supplied as OUTPUT

Consider the following T-SQL code snippet:
CREATE PROC dbo.SquareNum(#i INT OUTPUT)
AS
BEGIN
SET #i = #i * #i
--SELECT #i
END
GO
DECLARE #a INT = 3, #b INT = 5
EXEC dbo.SquareNum #a OUTPUT
EXEC dbo.SquareNum #b
SELECT #a AS ASQUARE, #b AS BSQUARE
GO
DROP PROC dbo.SquareNum
The result set is:
ASQUARE BSQUARE
----------- -----------
9 5
As can be seen, #b is not squared, b/c it was not passed-in as output parameter (no OUTPUT qualifier when passing in the parameter).
I would like to know if there is a way I could check within stored procedure body (dbo.SquareNum body in this case) to see if a parameter has indeed been passed in as an OUTPUT parameter?
------ THIS WILL GIVE YOU THE BOTH VALUE IN squared------
CREATE PROC dbo.SquareNum(#i INT OUTPUT)
AS
BEGIN
SET #i = #i * #i
--SELECT #i
END
GO
DECLARE #a INT = 3, #b INT = 5
EXEC dbo.SquareNum #a OUTPUT
EXEC dbo.SquareNum #b OUTPUT
SELECT #a AS ASQUARE, #b AS BSQUARE
GO
DROP PROC dbo.SquareNum
-----TO CHECK STORED PROCEDURE BODY-----
SELECT OBJECT_NAME(object_id),
OBJECT_DEFINITION(object_id)
FROM sys.procedures
WHERE OBJECT_DEFINITION(object_id) =(SP_NAME)
Actually, there is a very simple way!
Make the parameter optional by setting a default value (#Qty AS Money = 0 Below)
Then, pass a value OTHER THAN THE DEFAULT when calling the procedure. Then immediately test the value and if it is other than the default value you know the variable has been passed.
Create Procedure MyProcedure(#PN AS NVarchar(50), #Rev AS NVarchar(5), #Qty AS Money = 0 OUTPUT) AS BEGIN
DECLARE #QtyPassed AS Bit = 0
IF #Qty <> 0 SET #QtyPassed = 1
Of course that means the variable cannot be used for anything other than OUTPUT unless you have a default value that you know will never be used as an INPUT value.
You can do this by query to sys views:
select
p.name as proc_name,
par.name as parameter_name,
par.is_output
from sys.procedures p
inner join sys.parameters par on par.object_id=p.object_id
where p.name = 'SquareNum'
or check in Management Studio in database tree:
[database] -> Programmability -> Stored Procedures -> [procedure] -> Parameters
Maybe I'm wrong but I don't believe it's possible. OUTPUT is part of the stored procedure definition so you should know when a parameter is or not OUTPUT. There is no way to set it dynamically so I think it's pointless to determine by code when a parameter is output or not because you already know it.
If you are trying to write a dynamic code, Piotr Lasota's answer should drive you to the correct way to realize when a parameter is Output.
Use the following query to get the name of all the parameters and to check if it is a output parameter:
select name, is_output from sys.parameters

include the outptut of storedprocedure in select

I have a stored procedure like this:
create proc calcaulateavaerage
#studentid int
as
begin
-- some complicated business and query
return #result -- single decimal value
end
and then I want to
create proc the whole result
select * , ................................ from X where X.value > (calculateaverage X.Id)
It always gives an error that reads like "multi-part identifier calculateaverage couldn't be bound." Any idea how to solve that?
You don't want a stored procedure. You want a function.
Use Output variables to output the data out of stored procedure:
create proc calcaulateavaerage
#studentid int, #result int
as
begin
-- some complecated business and query
select #result = id from sometable;
end
-- Declaring output variable named result;
declare #result int;
-- Passing output variable to stored procedure.
exec calculateaverage 1, #result;
-- Now you can display the result or do whatever you like.
print #result

output parameter SQL Server 2005

How use output parameter from procedure?
Assuming that you have a sproc with an output parameter. You can call it and read the output value.
CREATE PROCEDURE AddOne
#val int,
#valPlusOne int out
AS
BEGIN
SET NOCOUNT ON;
SET #valPlusOne = #val + 1
END
GO
--This is used to store the output
declare #PlusOne int
--This calls the stored procedure setting the output parameter
exec AddOne 1, #valPlusOne=#PlusOne OUT
--This displays the value of the output param
select #Plusone

Resources