Why would a stored procedure return a 0 and the selected id? - sql

I have a stored procedure like this:
CREATE PROCEDURE [dbo].[create_myNewId]
(#parentId BIGINT)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [Mapping] (ParentId)
VALUES (#parentId)
SELECT SCOPE_IDENTITY();
END
This, when run on its own, returns the new id that has been assigned to the new row that's inserted with the parent id. However, when I do something like this:
DECLARE #NewId int
EXEC #NewId = create_myNewId #parentId = 33333
SELECT #NewId
When running this, the output window shows the result of the stored procedure, which returns an Id but #NewId always is 0. I fixed this by changing the stored procedure to use RETURN SCOPE_IDENTITY() but I was wondering why SELECT didn't work in this case?
I have my suspicions that it's something around the 0 being the success status being returned first from the stored procedure rather than the result, but was curious why this doesn't then happen when called directly from the client.

No! Write the procedure the right way:
CREATE PROCEDURE [dbo].[create_myNewId] (
#parentId bigint,
#outId bigint OUTPUT
) AS
BEGIN
SET NOCOUNT ON;
DECLARE #ids TABLE (id bigint);
INSERT INTO [Mapping](ParentId)
OUTPUT id INTO #ids
VALUES (#parentId);
SELECT #outId = id
FROM #ids;
END;
Then call this as:
DECLARE #NewId int;
EXEC create_myNewId #parentId = 33333, #NewId OUTPUT;
SELECT #NewId;
The OUTPUT clause is the recommend way to get results from a data-modification clause. The older methods using the *_IDENTITY() functions should be obsoleted.
Stored procedures do return values. These are integers that are designed to return status information. Other information should be returned via OUTPUT parameters.

Microsoft's design intent for stored procedures is that they always return an int to describe how successful the process undertaken by the procedure was. It's not intended to return a result data, and you're free to define the bits you want to return to describe succes, partial success etc. You could abuse it to return an integer result data (count query for example) if you wanted, but it's not the design intention
Executing a select query within a stored procedure creates a result set you can read on your client if the sproc is the kind that is intended to return data

My suggestion is to use an OUTPUT parameter. Not only will it be 'easier' to use when calling the stored procedure, it will also be clearer to the person calling the stored procedure.
CREATE PROCEDURE [dbo].[create_myNewId]
(#parentId BIGINT,
#myNewId BIGINT OUTPUT)
AS
BEGIN
SET NOCOUNT ON;
INSERT INTO [Mapping] ([ParentId])
VALUES (#parentId);
SET #myNewId = SCOPE_IDENTITY();
END;
GO
You would then call your stored procedure like this:
DECLARE #myNewId BIGINT;
EXECUTE [dbo].[create_myNewId] #parentId = 0, -- bigint
#myNewId = #myNewId OUTPUT; -- bigint
SELECT [This was just inserted] = #myNewId;

For anyone who has 0 as return value from a stored procedure, check if the stored procedure executes from the right database and only one procedure exists within the given context. Output parameters wouldn't be of any use if you ever plan to access the DB with ORM and the procedure returns an object's property.

Related

Get first row, first column value from stored procedure

I am calling a stored procedure (that I can't modify) that returns a single value via a SELECT at the end of the procedure. I need to use that value in my own procedure. How can I get that value?
Here is an example of the procedure I am calling that I can not modify:
CREATE PROCEDURE [dbo].[SP_poorlywritten] (
....
)
BEGIN
....
SELECT #lastkey;
RETURN (0);
END
And here is what I am trying to do, but it doesn't work because this gets the return value, and what I need is that SELECT value:
exec #next_key = SP_poorlywritten 'tablename',1;
How can I store the first column, first row value from a store procedure?
If you cannot modify the existing stored procedure, you will not be able to utilize the RETURN as you would like to.
An alternative may be to insert the output of the procedure's select statement into a temp table, and then query that directly to populate a variable.
That would look like this.
CREATE TABLE #tmp
(
LastKey INT
)
INSERT INTO #tmp
EXEC [dbo].[SP_poorlywritten]
See this existing post for more details on how you might accomplish this.
As Aaron Bertrand pointed out, RETURN is for error/status. If you were able to modify the stored procedure, you would want to utilize an output parameter instead of RETURN. This is how you would do that.
CREATE PROCEDURE proc_name
#Output int OUTPUT
AS
<do some stuff>
SET #Output = <some_value>
GO
DECLARE #Output int
EXEC proc_name #Output = #Output

How to use stored procedure return value into an insert statement?

I have a stored procedure like
CREATE PROCEDURE GetSerial (#param1 int, #param2 int)
AS
BEGIN
-- do some insert/updates, so I can't use function
DECLARE #value AS int;
SET #value = 3;
return #value;
END
Now I declare a table variable
DECLARE #Serials AS TABLE
(
ID int,
Value int
)
Now I wanna fill this table like
INSERT INTO #Serials (ID, Value)
SELECT 1, GetSerial(1,2) -- *How can I call this?
So, can anyone help me how can i call the GetSerial stored procedure inside the SELECT statement to fill my table?
I recommend you avoid getting into this pattern/thinking, because stored procedures only return INTs, and those ints are really intended to describe how well the operation went, not a result/data from the operation. Example: 0 => failed, 1=> succeeded. Not GetAgeInYears() => 29
https://learn.microsoft.com/en-us/sql/relational-databases/stored-procedures/return-data-from-a-stored-procedure?view=sql-server-2017 has a lot of info and concrete examples but in your specific case you'd need to execute the procedure and capture the result code into a variable then insert that:
DECLARE #ret INT;
EXEC #ret = GetSerial(1,2);
INSERT INTO #Serials VALUES(1, #ret);
Really you'd be better off using an output parameter or resultset if you have many values to return. See the above link for more

How to change data type of output of stored procedure? I want to output money data type but procedure always returns int

This is my procedure:
ALTER PROCEDURE spMaxOfInvoiceTotal
AS
BEGIN
DECLARE #max MONEY
SET #max = (SELECT MAX(InvoiceTotal) FROM Invoices)
PRINT #MAX
RETURN #MAX
END
GO
But when I execute, it returns int not money type.
DECLARE #return_value int
EXEC #return_value = [dbo].[spMaxOfInvoiceTotal]
SELECT 'Return Value' = #return_value
GO
As a result, a value is incorrect. It has to be 37966.19. But procedure returns 37966.
Even if I change #return_value money, I still get int. How to change procedure so return value would be money?
Stored procedure return value is used to return exit code, it is integer.
You should define output parameter
CREATE PROCEDURE mysp
#Maxval MONEY OUTPUT
http://msdn.microsoft.com/en-us/library/ms188655.aspx
What RDBMS is this for? SQL Server?
The value returned from a stored procedure in SQL Server is always INT and you can't change that - it's typically used to convey back a success/failure flag, or a "number of rows affected" information.
If you to "return" a MONEY (or better yet: DECIMAL) value - you can either use an OUTPUT parameter (which works fine for a single value), or you need to return a result set with that value.
So in your case, you could try something like:
CREATE PROCEDURE GetMaxOfInvoiceTotal
#MaxValue DECIMAL(20,4) OUTPUT
AS
BEGIN
SET #MaxValue = (SELECT MAX(InvoiceTotal) FROM Invoices)
END
GO
and then call this stored procedure like this:
DECLARE #RC INT
DECLARE #MaxValue DECIMAL(20,4)
EXECUTE #RC = [dbo].[GetMaxOfInvoiceTotal] #MaxValue OUTPUT
GO

Get scalar value from SELECT statement in stored proc, from within a stored proc

I know the preferred method for returning scalar values from stored procs is either using RETURN or an OUTPUT parameter. But lets say that I have a stored proc that returns the value using a select statement:
CREATE PROC spReturnNumber AS
SELECT 1
Is it possible to get this value from within another stored proc?
CREATE PROC spCheckNumber AS
EXEC spReturnNumber -- <-- get the return value here?
Clarification: I need a solution that doesn't require using an OUTPUT parameter, or using RETURN to return the value.
Thanks in advance.
You could use insert-exec to store the result of a stored procedure in a table:
declare #t table (col1 int)
insert #t exec spReturnNumber
return (select col1 from #t)
The definition of the table has to match the result set of the stored procedure.
Use an OUTPUT parameter instead of (or in addition to, if this procedure is used by other applications) the SELECT.
ALTER PROCEDURE dbo.spReturnNumber
#Number INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SET #Number = 1;
SELECT #Number;
END
GO
CREATE PROCEDURE dbo.spCheckNumber
AS
BEGIN
SET NOCOUNT ON;
DECLARE #Number INT;
EXEC dbo.spReturnNumber #Number = #Number;
SELECT #Number;
END
GO
If you can't change the original procedure, but you know its output will remain static, you could use a #temp table.
CREATE PROCEDURE dbo.spCheckNumber
AS
BEGIN
SET NOCOUNT ON;
CREATE TABLE #n(i INT);
INSERT #n(i) EXEC dbo.spReturnNumber;
DECLARE #Number INT;
SELECT #Number = i FROM #n;
END
GO
You can't get the SELECT value from "parent" procedure but you can get the return value like this:
CREATE PROC A AS
BEGIN
DECLARE #ret int
EXEC #ret = spReturnNumber
RETURN #ret
END
If you are unable to change the proc being called .. place the result set in a temp table [or table variable]:
CREATE TABLE #results (val INT)
DECLARE #someval int
INSERT #results
EXEC dbo.spCheckNumber
SELECT #someval =val from #results

How to query from a stored procedure in SQL Server?

Let say I have a simple Stored Procedure:
ALTER PROCEDURE [dbo].[myProc]
AS
BEGIN
SELECT * FROM myTable
END
How can I do a WHERE statement in Microsoft SQL Server Management Studio to the stored procedure? Something like that:
SELECT * FROM myProc WHERE x = 'a'; -- But that doesn't work...
It sounds like you're trying to make a "dynamic" stored procedure.
Something you might want to do is:
1) Insert the contents of your stored procedure into a temporary table
2) Use dynamic sql to apply a where condition to that temporary table.
Something like:
declare #as_condition varchar(500); --Your condition
create table #a
(
id bigint
)
insert into #a
execute sproc
declare #ls_sql varchar(max);
set #ls_sql = "select * from #a where " + #as_condition;
execute (#ls_sql);
SQL Server allows you to use INSERT INTO to grab a stored procedure's output. For example, to grab all processes with SPID < 10, use:
create table #sp_who (
spid smallint,
ecid smallint,
status nchar(30),
loginame nchar(128),
hostname nchar(128),
blk char(5),
dbname nchar(128),
cmd nchar(16),
request int)
insert into #sp_who execute sp_who
select * from #sp_who where spid < 10
You can't add a WHERE clause to a stored procedure like this.
You should put the clause in the sproc, like this:
ALTER PROCEDURE [dbo].[myProc]
#X VARCHAR(10)
AS
BEGIN
SELECT * FROM myTable WHERE x=#X
END
GO
The syntax for calling a stored procedure is through the use of EXECUTE not SELECT(e.g.):
EXECUTE dbo.myProc 'a'
I think you can't do that.
The command to execute a stored procedure is EXECUTE.
See some more examples of the EXECUTE usage.
I think its better to use a view or a table valued function rather than the suggested approach. Both allow you to pass parameters to the function
If you want the WHERE clause to be something you can "turn off" you can do this, passing in a predetermined value (e.g. -1) if the WHERE limitation is to be bypassed:
ALTER PROCEDURE [dbo].[myProc]
#X VARCHAR(10)
AS
BEGIN
SELECT * FROM myTable WHERE x=#X or #X = -1
END
GO
You must declare a variable in the store procedure which will be necessary to pass to run the stored procedure. Here is an example. Keep this in mind: Before AS you can simply declare any variable by using the # character, but after the AS you must write Declare to declare any variable, e.g., Declare #name nvarchar (50).
ALTER PROCEDURE [dbo].[myProc]
#name varchar (50)
AS
BEGIN
SELECT * FROM myTable
where name= #name
END