How to assign an output of a stored procedure that is nested in a stored procedure? - sql

I have a stored procedure that has a nested stored procedure that is executed when the parent stored procedure is executed.
Can the output of the nested stored procedure be assigned to a #variable and the output in a select statement?
EXEC #bat_key = [dbo].[client_icc_set_batch] - I can see the output here but would also like to include the output in a SELECT statement.
SELECT 'return_key' = #bat_key

I would just do it like this:
DECLARE #bat_key INT
CREATE TABLE #tmp (bat_key INT)
INSERT #tmp
EXEC [dbo].[client_icc_set_batch];
SET #bat_key = (
SELECT TOP 1 bat_key
FROM #tmp
order by bat_key DESC
);
SELECT 'return_key' + '=' + CONVERT(VARCHAR, #bat_key)
DROP TABLE #tmp

Related

different results of IN Condition

Don't quite understand IN statement. First variant works fine:
select manufacturers.id
from manufacturers
where manufacturers.id in (select manufacturerId
from pcs group by manufacturerId
having count(manufacturerId) > 1)
But when I make subquery a procedure:
CREATE PROCEDURE [dbo].Get_manufacturers #productType varchar(50)
as
begin
declare #query varchar(500)
set #query='select manufacturerId from ' + QuoteName(#productType) + '
group by manufacturerId having count(manufacturerId) > 1'
declare #t table (manufacturerId int)
insert into #t exec(#query)
select manufacturerId from #t;
end
select manufacturers.id
from manufacturers
where manufacturers.id in (Get_manufacturers 'pcs')
I get an error: Msg 102, Level 15, State 1, Line 4
Incorrect syntax near 'pcs'
Get_manufacturers 'pcs' works properly. Where am I wrong?
Don't quite understand IN statement
...
Get_manufacturers 'pcs' works properly - it returns a table
You misunderstand both stored procedures and IN condition.
From IN (Transact-SQL):
test_expression [ NOT ] IN
( subquery | expression [ ,...n ]
)
What the stored procedure returns is not a subquery, neither it's an expression.
Here is a link to understand what subquery is Using a Subquery in a T-SQL Statement
A subquery is a SELECT statement that is nested within another T-SQL
statement
So stored procedure is not a subquery, it's just not a SELECT statement.
But even when you say that stored procedures returns a table it's wrong: you can JOIN a table to another table but you cannot join the result of stored procedure.
And even if you "see" the result set returned by a procedure as a "table" it's not a table.
Based on Rokuto and Gordon Linoff suggestions, Alter the procedure by omitting the table declaration:
ALTER PROCEDURE [dbo].Get_manufacturers #productType nvarchar(50)
as
begin
declare #query nvarchar(500)
set #query= N'select manufacturerId from ' + QuoteName(#productType) + '
group by manufacturerId having count(manufacturerId) > 1'
---declare #t table (manufacturerId int)
---insert into #t exec(#query)
---select manufacturerId from #t;
exec(#query)
end
GO
Then, Use a temporary table to fill in the results of the stored procedure.
IF(OBJECT_ID('tempdb..#tmp_manufacturers') IS NOT NULL)
BEGIN
DROP TABLE #tmp_manufacturers
END
CREATE TABLE #tmp_manufacturers
(
manufacturerId int
)
INSERT INTO #tmp_manufacturers (manufacturerId)
EXEC dbo.Get_manufacturers 'pcs'
lastly, add it to your IN condition.
select m.id
from manufacturers M
where m.id IN (select t.manufacturerId From #tmp_manufacturers T)
As #Gordon Linoff said, procedures does not return tables.
But, if you want to store output data from stored procedures, you need to put it into table e. g.:
DECLARE #manufactures TABLE (Id int)
INSERT INTO #manufactures
exec Get_manufacturers 'pcs'
select manufacturers.id
from manufacturers
where manufacturers.id IN (SELECT Id FROM #manufactures)
Instead of table variable, you can use temporary table.

Replacing function call with procedure execution in sql

I had a function called dbo.Match.It was an inline TVF that I replaced with a procedure called dbo.Match that has a select statement at its end to select rows from a table so that I can direct the results of select query when I execute dbo.Match to a temporary table called #Temp.
Now if it was a function, I was using this query :
if #MotherFN is not null
begin
SELECT #constVal = FunctionWeight
FROM dbo.FunctionWeights
WHERE FunctionWeights.FunctionId = 20;
INSERT INTO #Temp2
(RowNumber,ValFromUser,ColumnName,ValFromFunc,FuncWeight,percentage)
SELECT RowId,
#MotherFN ,
'mothersfirstname'
,PercentMatch,
#constVal,
PercentMatch * #constVal
FROM dbo.Match(#MotherFN)
end
Now, I need to execute dbo.Match procedure instead of dbo.Match function.How I may make this execution call and insert data in #Temp table like I was doing with function call ?
Problem : Calculating PercentMatch * #constVal and inserting in #Temp in same step efficiently. Procedure dbo.Match would return rowId and PercentMatch only. I need to insert values of RowId and PercentMatch in #Temp along with value of #constVal and a value for result of multiplication of PercentMatch and #constval
I would make the procedure accept these following parameters
#MotherFN , #constVal
And do the following inside the procedure , in select statement that returns the procedure's result set.
SELECT RowId,
#MotherFN , --<-- In proc definition
'mothersfirstname'
,PercentMatch,
#constVal, --<-- In proc definition
PercentMatch * #constVal --<-- In proc definition
And for insert simply do
INSERT INTO #TemP (RowNumber,ValFromUser,ColumnName
,ValFromFunc,FuncWeight,percentage)
Exec dbo.Match(#MotherFN , #constVal)
You options are more limited with a procedure.
You can use insert into ... exec ... to insert the results of the procedure into a temporary table, but you can't really combine it with another query. (Well you could use openrowset with dynamic SQL, but that will get nasty very quickly).
For example something like:
if #MotherFN is not null
begin
select
#constVal = FunctionWeight
from
dbo.FunctionWeights
where
FunctionWeights.FunctionId = 20;
insert into #Temp2 (
RowId, ColumnName, ValFromFunc
) exec
dbo.Match(#MotherFN);
update
#Temp2
set
ValFromUser = #MotherFN,
FuncWeight = #constVal,
percentage = PercentMatch * #constVal;
end;

How can I call and get back the results of an SP from another Stored Procedure

I have this stored procedure:
CREATE PROCEDURE [dbo].[sp_get_correct_responses]
#QuestionUId UNIQUEIDENTIFIER
AS
BEGIN
...
-- This is the last part of the SP. I need to use the output
-- value of #AnswerGridCorrect in the calling SP
SELECT #AnswerGridCorrect = Correct
FROM Concatenated
WHERE RowNumber = ColumnCount
END
How can I call the stored procedure from another stored procedure, pass it the #QuestionUId parameter and put the returned variable #AnswerGridCorrect into a variable declared in the calling procedure?
Update: Here's the proposed answer:
CREATE PROCEDURE [dbo].[sp_get_correct_responses]
#QuestionUId UNIQUEIDENTIFIER,
#output VARCHAR(20) output
AS
BEGIN
select #QuestionUId
DECLARE #AnswerGridCorrect VARCHAR(20)
DECLARE #QuestionId int;
SELECT #QuestionId = QuestionId
FROM dbo.Question
Where QuestionUId = #QuestionUId;
Select #questionId;
WITH Partitioned AS (
SELECT ROW_NUMBER() OVER (PARTITION BY QuestionId ORDER BY AnswerId ASC) AS RowNumber,
COUNT(1) OVER (PARTITION BY QuestionId) AS ColumnCount,
CONVERT(VARCHAR(MAX), Correct) AS Correct
FROM dbo.Answer
WHERE [QuestionId] = #QuestionId
),
Concatenated AS (
SELECT RowNumber, ColumnCount, Correct FROM Partitioned WHERE RowNumber = 1
UNION ALL
SELECT P.RowNumber,
P.ColumnCount,
C.Correct + P.Correct AS Correct
FROM Partitioned P
INNER JOIN Concatenated C
ON P.RowNumber = C.RowNumber + 1
)
SET #output = (SELECT Correct
FROM Concatenated
WHERE RowNumber = ColumnCount)
RETURN
END
You could have a temp table in the other stored procedure and populate it with the results of this one:
INSERT INTO #table
Exec sp_get_correct_responses #QuestionUId
The other way would be to modify sp_get_correct_responses to produce an output as you are expecting only one value.
CREATE PROCEDURE [dbo].[sp_get_correct_responses]
#QuestionUId UNIQUEIDENTIFIER,
#output VARCHAR(20) output
AS
BEGIN
...
-- This is the last part of the SP. I need to use the output
-- value of #AnswerGridCorrect in the calling SP
SELECT #output = Correct
FROM Concatenated
WHERE RowNumber = ColumnCount
RETURN
END
And in your other SP:
DECLARE #output VARCHAR(20)
EXEC sp_get_correct_responses
#QuestionUId,
#output output
SELECT #output
You can make one table variable in parent SP and insert result of child SP in that like below :
DECLARE #TempTable TABLE(AnswerGridCorrect INT)
INSERT INTO #TempTable
EXEC [dbo].[sp_get_correct_responses] #QuestionUId

SQL server stored procedure return a table

I have a stored procedure that takes in two parameters. I can execute it successfully in Server Management Studio. It shows me the results which are as I expect. However it also returns a Return Value.
It has added this line,
SELECT 'Return Value' = #return_value
I would like the stored procedure to return the table it shows me in the results not the return value as I am calling this stored procedure from MATLAB and all it returns is true or false.
Do I need to specify in my stored procedure what it should return? If so how do I specify a table of 4 columns (varchar(10), float, float, float)?
A procedure can't return a table as such. However you can select from a table in a procedure and direct it into a table (or table variable) like this:
create procedure p_x
as
begin
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t values('a', 1,1,1)
insert #t values('b', 2,2,2)
select * from #t
end
go
declare #t table(col1 varchar(10), col2 float, col3 float, col4 float)
insert #t
exec p_x
select * from #t
I do this frequently using Table Types to ensure more consistency and simplify code. You can't technically return "a table", but you can return a result set and using INSERT INTO .. EXEC ... syntax, you can clearly call a PROC and store the results into a table type. In the following example I'm actually passing a table into a PROC along with another param I need to add logic, then I'm effectively "returning a table" and can then work with that as a table variable.
/****** Check if my table type and/or proc exists and drop them ******/
IF EXISTS (SELECT * FROM sys.objects WHERE type = 'P' AND name = 'returnTableTypeData')
DROP PROCEDURE returnTableTypeData
GO
IF EXISTS (SELECT * FROM sys.types WHERE is_table_type = 1 AND name = 'myTableType')
DROP TYPE myTableType
GO
/****** Create the type that I'll pass into the proc and return from it ******/
CREATE TYPE [dbo].[myTableType] AS TABLE(
[someInt] [int] NULL,
[somenVarChar] [nvarchar](100) NULL
)
GO
CREATE PROC returnTableTypeData
#someInputInt INT,
#myInputTable myTableType READONLY --Must be readonly because
AS
BEGIN
--Return the subset of data consistent with the type
SELECT
*
FROM
#myInputTable
WHERE
someInt < #someInputInt
END
GO
DECLARE #myInputTableOrig myTableType
DECLARE #myUpdatedTable myTableType
INSERT INTO #myInputTableOrig ( someInt,somenVarChar )
VALUES ( 0, N'Value 0' ), ( 1, N'Value 1' ), ( 2, N'Value 2' )
INSERT INTO #myUpdatedTable EXEC returnTableTypeData #someInputInt=1, #myInputTable=#myInputTableOrig
SELECT * FROM #myUpdatedTable
DROP PROCEDURE returnTableTypeData
GO
DROP TYPE myTableType
GO
Consider creating a function which can return a table and be used in a query.
https://msdn.microsoft.com/en-us/library/ms186755.aspx
The main difference between a function and a procedure is that a function makes no changes to any table. It only returns a value.
In this example I'm creating a query to give me the counts of all the columns in a given table which aren't null or empty.
There are probably many ways to clean this up. But it illustrates a function well.
USE Northwind
CREATE FUNCTION usp_listFields(#schema VARCHAR(50), #table VARCHAR(50))
RETURNS #query TABLE (
FieldName VARCHAR(255)
)
BEGIN
INSERT #query
SELECT
'SELECT ''' + #table+'~'+RTRIM(COLUMN_NAME)+'~''+CONVERT(VARCHAR, COUNT(*)) '+
'FROM '+#schema+'.'+#table+' '+
' WHERE isnull("'+RTRIM(COLUMN_NAME)+'",'''')<>'''' UNION'
FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = #table and TABLE_SCHEMA = #schema
RETURN
END
Then executing the function with
SELECT * FROM usp_listFields('Employees')
produces a number of rows like:
SELECT 'Employees~EmployeeID~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("EmployeeID",'')<>'' UNION
SELECT 'Employees~LastName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("LastName",'')<>'' UNION
SELECT 'Employees~FirstName~'+CONVERT(VARCHAR, COUNT(*)) FROM dbo.Employees WHERE isnull("FirstName",'')<>'' UNION
You can use an out parameter instead of the return value if you want both a result set and a return value
CREATE PROCEDURE proc_name
#param int out
AS
BEGIN
SET #param = value
SELECT ... FROM [Table] WHERE Condition
END
GO
I had a similar situation and solved by using a temp table inside the procedure, with the same fields being returned by the original Stored Procedure:
CREATE PROCEDURE mynewstoredprocedure
AS
BEGIN
INSERT INTO temptable (field1, field2)
EXEC mystoredprocedure #param1, #param2
select field1, field2 from temptable
-- (mystoredprocedure returns field1, field2)
END
The Status Value being returned by a Stored Procedure can only be an INT datatype. You cannot return other datatypes in the RETURN statement.
From Lesson 2: Designing Stored Procedures:
Every stored procedure can return an integer value known as the
execution status value or return code.
If you still want a table returned from the SP, you'll either have to work the record set returned from a SELECT within the SP or tie into an OUTPUT variable that passes an XML datatype.
HTH,
John
Though this question is very old but as a new in Software Development I can't stop my self to share what I have learnt :D
Creation of Stored Procedure:
CREATE PROC usp_ValidateUSer
(
#UserName nVARCHAR(50),
#Password nVARCHAR(50)
)
AS
BEGIN
IF EXISTS(SELECT '#' FROM Users WHERE Username=#UserName AND Password=#Password)
BEGIN
SELECT u.UserId, u.Username, r.UserRole
FROM Users u
INNER JOIN UserRoles r
ON u.UserRoleId=r.UserRoleId
END
END
Execution of Stored Procedure:
(If you want to test the execution of Stored Procedure in SQL)
EXEC usp_ValidateUSer #UserName='admin', #Password='admin'
The Output:
create procedure PSaleCForms
as
begin
declare
#b varchar(9),
#c nvarchar(500),
#q nvarchar(max)
declare #T table(FY nvarchar(9),Qtr int,title nvarchar (max),invoicenumber nvarchar(max),invoicedate datetime,sp decimal 18,2),grandtotal decimal(18,2))
declare #data cursor
set #data= Cursor
forward_only static
for
select x.DBTitle,y.CurrentFinancialYear from [Accounts Manager].dbo.DBManager x inner join [Accounts Manager].dbo.Accounts y on y.DBID=x.DBID where x.cfy=1
open #data
fetch next from #data
into #c,#b
while ##FETCH_STATUS=0
begin
set #q=N'Select '''+#b+''' [fy], case cast(month(i.invoicedate)/3.1 as int) when 0 then 4 else cast(month(i.invoicedate)/3.1 as int) end [Qtr], l.title,i.invoicenumber,i.invoicedate,i.sp,i.grandtotal from ['+#c+'].dbo.invoicemain i inner join ['+#c+'].dbo.ledgermain l on l.ledgerid=i.ledgerid where (sp=0 or stocktype=''x'') and invoicetype=''DS'''
insert into #T exec [master].dbo.sp_executesql #q
fetch next from #data
into #c,#b
end
close #data
deallocate #data
select * from #T
return
end
Here's an example of a SP that both returns a table and a return value. I don't know if you need the return the "Return Value" and I have no idea about MATLAB and what it requires.
CREATE PROCEDURE test
AS
BEGIN
SELECT * FROM sys.databases
RETURN 27
END
--Use this to test
DECLARE #returnval int
EXEC #returnval = test
SELECT #returnval

How do I define a stored procedure that returns table?

For example I have this stored procedure:
create procedure MyStoredProcedure
as
begin
select *
from X,Y
where x.Id = Y.ID
end
return #table table(X.tTitle, Y.Description)
I want return table and when use table in another query
Stored procedures cannot1 be composed into other queries as a source of rows - is there a reason why it has to be a stored procedure? A user defined function has almost the same amount of expressability as a stored procedure and can easily be a source of rows in the FROM clause of another query.
Something like:
create function MyFunction()
returns table
as
return (select X.tTitle,Y.Description
from X
inner join Y
on x.Id = Y.ID)
1 Ignoring INSERT...EXEC since it does nothing for composition, and OPENROWSET isn't always a viable approach.
Try this:
create procedure MyStoredProcedure
as
begin
select X.*,Y.*
From X INNER JOIN Y ON X.Id=Y.ID
end
This will select all data from tables X and Y.
Try This Way:
CREATE PROCEDURE [dbo].[MyStoredProcedure]
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
Declare #ID int
set #ID =(select ID From X INNER JOIN Y ON X.Id=Y.ID)
IF #ID > 0
BEGIN
return #table table(X.tTitle,Y.Description)
END
END
you can simply Create a Procedure and then, Try this:
CREATE PROCEDURE MyStoredProcedure
AS
BEGIN
SELECT tTitle ,
Description
FROM X
JOIN Y ON Y.ID = X.ID
END
You can use temp tables or table variables.
Like this:
CREATE TABLE #TABLE
(
COLUMN DEFINITION
)
INSERT INTO #TABLE
EXEC <YOUR STORED PROCEDURE>
SELECT *
FROM #TABLE
DROP TABLE #TABLE
You can insert your stored procedure inside the temp table so you can use it as well as a table.
Note that temp table names should start with #.
Somethings like this you most write
CREATE PROCEDURE <SP_Name>
AS
BEGIN
Select ......
End