How to set the result of exec stored procedure to a variable? - sql

I need to exec a stored procedure and store its scalar result to a local variable inside a stored procedure.
How to implement?
E.G.
CREATE PROCEDURE [dbo].GetNthNo AS
DECLARE #a INT
DECLARE #d INT
DECLARE #n INT
DECLARE #S INT
SET #S=EXEC spGetNthNo #a,#d,#n
SELECT #S
Please help.

Instead of:
SET #S=EXEC spGetNthNo #a,#d,#n
You need:
EXEC #S = spGetNthNo #a,#d,#n
And then within the procedure, you need something like:
RETURN 100
or:
RETURN #x
for the value you want for #S after the procedure executes.
You can also use output parameters. Combined example:
IF OBJECT_ID('tempdb..#example') IS NOT NULL DROP PROCEDURE #example
GO
CREATE PROCEDURE #example
#output_param INT OUTPUT
AS BEGIN
SET #output_param = 100
RETURN 200
END
GO
DECLARE #return INT, #param INT
EXEC #return = #example #output_param = #param OUTPUT
SELECT #return as [return value], #param as [output parameter]

Try something like that
CREATE PROCEDURE Test
#RetVal INT OUT
AS
BEGIN
SET #RetVal = 99
END
DECLARE #X INT
EXEC Test #X OUT
PRINT #X
Edit: [comment following posting of T-SQL snippet in question]
You seem to need a wrapper, around the spGetNthNo Stored Procedure, maybe because this existing procedure doesn't return its result in the way that is desired. An alternative to a wrapper may simply be to modify [ever so slightly] spGetNthNo itself, so it works as desired in the first place (provided the method is not currently in use with its existing API).
Regardless of whether the changes will be in the original SP or in a wrapper, there are two distinct ways of retrieving data from an SP:
With output variables (as shown above)
By having the SP return a "recordset", i.e. a table made of rows (records) and columns (fields). (This is done by having a SELECT statement towards the end of the SP, as show in the question snippet)
With the output variable approach, the data is readily placed in the variables by the time the SP returns. With the recordset apporach, the calling logic needs to "consume" the data returned, in a similar fashion that it would from a SELECT statement.
Aside from the way the returned data is consumed, there are a few differences between these approaches.
The most obvious one is that the "recordset" approach allows the returning more values: one would have to explicitly declare say 30 variables (with some naming convention aimed at helping with the two-dimensional nature of the table) to emulate a the returns of a SP which "SELECT TOP 10 a, b, c FROM myTable". Also the SP would have to explicitly set each of the these output variables.
Another related but more subtle difference is that the recordset approach allows returning a number of rows and columns that is undefined at the time of the call. The number and types of the variables do not need to be expressed beforehand, rather they come with the metadata surrounding the recordset.
In short: the output variable approach is more suited to return a fixed set of a few variables, such as status code, maximum or minim value (or other aggregate values and calculations), or also, a few fields from a expected single record. The Recordset approach is used when the purpose of the stored procedure is to effectively provide a table-like result, or when it returns very many values, such as a long [and evolving] list of aggregate values, etc.

Related

Return a single value and multiple OUT parameter in Stored Procedure

I read an article about Stored Procedures which said:
A stored procedure can return a single values such as a number or text value or a result set
I am confused, because if we declare multiple OUT parameters, the we can have multiple output but it said that we can have only a single value?
EDIT:
This is The Article
In SQL Server, a stored procedure can actually return a value -- always an integer. This is usually a status value and is quite separate from the output parameters.
So you can can have:
execute #retval = usp_myproc #x1 output, #x2 output;
The returned value is generally not data, but a status.
That statement is not entirely correct.
There are three ways of returning data from a procedure to a calling program: result sets, output parameters, and return codes.
See Return Data from a Stored Procedure
This link will walk you through the 3 approaches.

How to manipulate resultset returned by a stored procedure called inside the stored procedure in DB2

I need to create a stored procedure (SP_CALLER) that will call another stored procedure (SP_CALLED) and select its returned resultset.
How can we query the returned result set??
CREATE OR REPLACE PROCEDURE SCHEMANAME.SP_CALLER(#PARAM1 INT, #PARAM2 VARCHAR)
DYNAMIC RESULT SETS 1
P1:BEGIN
DECLARE VALUE1 INT DEFAULT 0;
DECLARE VALUE2 VARCHAR DEFAULT 'TEST';
CALL SCHEMANAME.SP_CALLED #XPARAM1=VALUE1, #XPARAM2=VALUE2; --<-- returns a result set
SELECT *
INTO #TEMPTABLE
FROM (resultsetquery); --<-- from the returned result set of sp_called
SELECT *
FROM #TEMPTABLE a,
SCHEMANAME.TABLE2 b
WHERE a.COL1 = #PARAM1 AND b.COL2 = #PARAM2;
END P1
UPDATE 04/04/2019:
The docs were really helpful, but i was stuck here.. how can i query the resultset that allocated to this variable ('cur') and return it as the new result set of my stored procedure (SCHEMANAME.SP_CALLER)???
CREATE OR REPLACE PROCEDURE SCHEMANAME.SP_CALLER() DYNAMIC RESULT SETS 1
P1:BEGIN
DECLARE loc_cursor RESULT_SET_LOCATOR VARYING;
CALL SCHEMANAME.SPNAME();
ASSOCIATE RESULT SET LOCATOR (loc_cursor) WITH PROCEDURE SCHEMANAME.SPNAME;
ALLOCATE cur CURSOR FOR RESULT SET loc_cursor;
CLOSE cur;
END P1
This is covered in the documentation.
The key details to learn about are locators, associate result set locators and then allocate ... cursor for result set. After that is done, your calling procedure can treat the cursor just like any other (fetching rows , close etc).
So if your nested procedures returns 1 result set, your calling sproc will declare a locator, associate the result-set locator with your called-procedure, then allocate a cursor to consume the result-set. Study the documentation for each of the involved statements.
Apart from the above, if you will always filter the result-set, why not make a procedure that performs the filtering at source (to avoid slow double filtering)? You can also have a procedure create a session-table and have callers access that session-table. Or use a table-function to return exactly what is needed?

How to stop results of nested stored procedure showing up at top level?

I've made an alteration to an existing stored procedure (dbo.pr1) so that it now calls a second stored procedure (dbo.pr2).
Both of these stored procedures return data with a final SELECT query.
In dbo.pr1 I've now added the line:
EXEC #var1 = dbo.pr2
I've done this in order to assign the values in dbo.pr2 to the variable #var1 (dbo.pr2 returns a single bit).
However, now when I execute dbo.pr1 I get two results back instead of the expected one. I get the SELECT query results at the end of dbo.pr1 but I also get the SELECT query result from dbo.pr2.
I cannot alter dbo.pr2 as it's being used elsewhere in the system. Is there a way that I can stop its result showing up when I execute dbo.pr1?
Do something with what is returned in the caller,
SET NOCOUNT ON;
...
DECLARE #resultsOfPr2 TABLE
(
...
);
INSERT #resultsOfPr2
EXEC #var1 = [dbo].[pr2];
Fiddle here
Note: I'm assuming [dbo].[pr2] selects a single result set.

SQL Server Stored Procedure Multiple Insert in a single table from Array

I am using a stored procedure to insert records into a table. And do this at least 12 times in a loop to insert multiple records which is very inefficient.
here is the procedure as CREATED
Create PROC [dbo].[SP_INSERT_G_SAMPLING]
#GameID INT,
#ScoreID INT
as
begin
INSERT INTO GAMESCORE (GAMEID, SCOREID) VALUES
(#GameID, #ScoreID)
end
I pass on the values ex(1,3) and loop with more values from the website.
I want to however pass on all the values at one time like (1,3),(4,5),(8,9)
and then alter the above procedure to receive and insert multiple rows.
ALTER PROC [dbo].[SP_INSERT_G_SAMPLING]
#totalinsert nvarchar(Max)
INSERT INTO GAMESCORE (GAMEID, SCOREID) VALUES
(#totalinsert)
with #totalinsert being like (1,3),(4,5),(8,9) pushed from the webpage.
any help is greatly appreciated
What you're going to have to do is write a table valued function which accepts the multi-value string and breaks it out into a table object. If you can change your source to use a record delimiter instead of having comma sets it would be slightly easier to process. An example of that would look like this.
The below is pure psuedo and has not been validated in any way, just meant to give you a rough idea of where to go.
ex: #TotalInsert = 1,2|4,5|8,9
DECLARE #Results TABLE
(
value1 INT,
value2 INT
)
DECLARE #setlist VARCHAR(max);
WHILE Len(#TotalInsert) > 0
BEGIN
SET #setlist = LEFT(#totalinsert, Charindex('|', #totalinsert))
INSERT INTO #results
SELECT LEFT(#setlist, Charindex(',', #setlist) - 1),
RIGHT(#setlist, Charindex(',', Reverse(#setlist)) + 1)
SET #totalinsert = RIGHT(#totalinsert, Len(#totalinsert) - Len(#setlist))
END
I'm assuming you're using .NET for your website since you're also using SQL Server.
Have a look at table valued parameters, this page also includes a nice example of how to use the table valued parameters in .NET.
Check here for a better example of making a stored procedure with a table valued parameter in T-SQL.
Here is the full discussion:
http://www.sommarskog.se/arrays-in-sql-2005.html#XMLlist%20of%20values
Personally, I sent xml to the stored procedure, I "shred it" into #variable or #temp tables, then I do my INSERT/UPDATE/MERGE/DELETE from there.
Here is a fuller discussion on xml-shredding.
http://pratchev.blogspot.com/2007/06/shredding-xml-in-sql-server-2005.html
My personal trick is to create a strong dataset, populate the strong dataset with rows, and use the ds.GetXml() to send the xml down to the TSQL. With a strong dataset, I get strong-typing when populating the values. But at the end of the day, dataset is just some super fancy xml.

SQL Server setting multiple variables

I have 7 different stored procedures that take in a number of parameters and insert data into 7 different tables.
I am now creating a main stored procedure to execute these 7 procedures with all of the data they need. All of the data they need is ONE table (CommonImport).
Should I take all of the parameters I need in this main stored procedure?
Or
Only take in the ID of the row that needs to be inserted into these 7 separate tables and get the data directly from the table.
I think the second option is best. BUT, how do I set all the variables in the main stored procedure to all of the data from the (CommonImport) table?
Essentially, how do I set a bunch of declared variables to the values from a specific row in the CommonImport table?
Thanks
Passing an ID:
The benefit here is that you simplify all the interfaces to your stored procedures.
This makes it easier to code against. If you end up calling the SP from speveral places, you just need to use a single parameter, rather than loading and passing several parameters.
Passing n Variables:
Then benefit here is that you 'decouple' your Stored Procedures from the holding table.
This means that you could simply call the stored procedures directly, without having any data in the table. This may be useful in the future, if data arrives in a new way, or for unit testing, etc.
Which is best:
I don't think that there is a straight answer to this, it's more a case of preference and opinion.
My opinion is that the less tightly coupled things are, the better. It's more flexible in the face of changes.
The way I'd do it is as follows...
CREATE PROCEDURE main_by_variable #v1 INT, #v2 INT, ...
BEGIN
EXEC sub_part_1 #v1, #v3
EXEC sub_part_2 #v2
EXEC sub_part_3 #v2, #v3
...
END
CREATE PROCEDURE main_by_id #id INT AS
BEGIN
DECLARE
#v1 INT,
#v2 INT,
...
SELECT
#v1 = field1,
#v2 = field2
FROM
holding_table
WHERE
id = #id
EXEC main_by_variable #v1, #v2, ...
END
GO;
By having the main_by_variable procedure, you have the felxibility, such as testing all the sub procedures, without actually having to enter any data into the holding table. And that flexibility is part of the sub procedures as well.
But, for convenience, you may find that using main_by_id is more tidy. As this is just a wrapper around main_by_variable, all you are doing is encapsulating a single step in the process (getting the data out of the table).
It also allows you to put a transaction around the data gathering part, and delete the data out of the table. Or many other options. It's flexible, and I like flexible.
I would suggest accepting all variables as parameters and define default values for them, so SP users can use it either with single ID parameter or with an other as weel by specifying those directly
CREATE PROCEDURE MainSP
#ID int,
#CustomParameter varchar(10) = NULL,
#CustomParameter1 DateTime = NULL,
...
In this way SP would be pretty flexible