Stored procedured doesnt give the result back - sql

I have written such a stored procedure, it must return a result, but it doesnt do that. it returns only a message that stored procedure runs successfully.
How should I change my SP?
CREATE PROCEDURE TestTVP
(
#param1 int,
#param2 int,
#a int OUTPUT
)
as
SET NOCOUNT ON
DECLARE #T1 as TABLE
(
PK INT IDENTITY NOT NULL,
Wert INTEGER,
Name INTEGER
)
INSERT INTO #T1(Wert,Name) VALUES (#param1,#param2)
return select count(*) from #T1
GO
exec TestTVP '1','22'

you have to pass OUTPUT parameter
declare #z int
exec TestTVP '1','22' ,#z output
and remove return from Stored Procedure make it only
...
select count(*) from #T1

You can use out parameter if you want the output :
DECLARE #Z int
EXEC TestTVP '2', '22',#z out

Related

Get result parameter of stored procedure in exec clause

I have a stored procedure that returns multiple parameters:
CREATE PROCEDURE [dbo].[TestSP]
#Test1 INT
, #Test2 UNIQUEIDENTIFIER
--some inserts and alters here
SELECT TOP 1
#Parameter1 AS Design
, #Parameter2
, #Parameter3
FROM Table
I want to use EXEC into another stored procedure and get ONLY #Parameter1 (Design)
So I want to get #Parameter1 after EXEC stored procedure, so I think about OUTPUT, but it doesn't work, is there a way to achieve this?
CREATE PROCEDURE [dbo].[SecondStoredProcedure]
#Sender1 INT
, #Sender2 UNIQUEIDENTIFIER
DECLARE #ReturnedParameter1 INT
EXEC [dbo].[TestSP] #Test1 = #Sender1, #Test2 = #Sender2 OUTPUT [Design]
INTO #ReturnedParameter1
SELECT #ReturnedParameter1
That procedure creates a resultset, and has no output parameters. You can capture a resultset with insert into ... exec, like this:
use tempdb
go
CREATE PROCEDURE [dbo].[addDesign]
#Test1 INT
,#Test2 UNIQUEIDENTIFIER
as
begin
--some inserts and alters here
SELECT
1 AS Design
, 2 as Foo
, 3 as Bar
end
go
declare #rv table(Design int, Foo int, Bar int)
declare #test2 uniqueidentifier = newid()
insert into #rv
exec addDesign 1, #test2
declare #design int = (select Design from #rv)
select #design
I suggest using an output parameter as explained in the official docs.
Here is how your code might look in this case:
use tempdb
go
create procedure [dbo].[addDesign]
(
#Test1 int
, #Test2 uniqueidentifier
, #Design int out
)
as
begin
set nocount on;
--some inserts and alters here
-- Set the return parameter
set #Design = #Parameter1;
-- Select the return results
SELECT TOP 1
#Parameter1
, #Parameter2
, #Parameter3
FROM dbo.MyTable;
-- Return status code, proc ran OK
return 0;
end
go
create procedure [dbo].[SecondStoredProcedure]
(
#Sender1 int
, #Sender2 uniqueidentifier
)
as
begin
set nocount on;
declare #ReturnedParameter1 int;
exec dbo.TestSP #Test1 = #Sender1, #Test2 = #Sender2, #Design = #ReturnedParameter1;
select #ReturnedParameter1;
-- Return status code, proc ran OK
return 0;
end
go
Note: This demonstrates the 3 ways information can be returned from a stored procedure, the result code (only 1), output parameters (0-N) and result sets (0-N).

Getting error "An INSERT EXEC statement cannot be nested"

I've hit a problem with the insert...exec, and I can't find a solution online that will work. I have a stored procedure that retrieves data from an API. It does this by building a command line, running it through xp_cmdshell, and capturing the output to a table (using an insert...exec).
The stored procedure works perfectly, and formats the required data into a nice table
I'm now trying to implement this into my db, but this needs to be called from a number of other stored procedures. They need to be able to see the results of the initial stored procedure, but I've hit a "An INSERT EXEC statement cannot be nested" error, and it won't let me capture the output
I've tried various solutions I've seen suggested online, but so far none of them have worked. The initial stored procedure is calling a command line, so I can't find any other way to call it and capture the output, other than using an insert.....exec, but I still need the formatted output.
I have tried to convert my stored procedure to a function, but I cannot run the xp_cmdshell. I've also looked at getting the initial stored procedure to return the table as an output parameter (even if I create it with a type), but the stored procedure won't allow that
I've also looked at using openset, but I need to be able to pass a parameter to the stored procedure, and I don't think openset will allow this. What could I try next?
EDIT: I've put together a simple example of what I'm trying to do. The stored procedure is retrieving data from a command line. I'm just using an echo command to fudge the data, but in reality, this command line is calling an API, and receiving JSON back. The JSON is then formatted into a SQL table, and output. As this is an API call, I can't see any other way to do it without an insert...exec xp_cmdshell, but this means I cannot capture the output of the stored procedure and use it
create procedure usp_retrieveAPIdata
#inparameter int
as
begin
declare #APIcall varchar(200)
--this would normally be an API call, returning a JSON array
set #APICall='echo f1:"foo" & echo f2:"bar" & echo f1:"Hello" & echo f2:"World"'
declare #resulttable table
(outputfield varchar(100),ID int identity)
insert into #resulttable
exec xp_cmdshell #APICall
declare #formattedtable table
(field1 varchar(100),field2 varchar(100))
declare #rownum int =0
declare #field1 varchar(100)
declare #field2 varchar(100)
declare #currentfield varchar(100)
while exists (select * from #resulttable where ID>#rownum)
begin
set #rownum=#rownum+1
select #currentfield=outputfield from #resulttable where ID=#rownum
if #currentfield like 'f1%'
begin
set #field1=replace(#currentfield,'f1:','')
end
if #currentfield like 'f2%' and #rownum<>1
begin
set #field2=replace(#currentfield,'f2:','')
insert into #formattedtable (field1,field2) values (#field1,#field2)
end
end
select * from #formattedtable
end
go
declare #resulttable table (field1 varchar(100),field2 varchar(100))
insert into #resulttable
exec usp_retrieveAPIdata 1
This is the problem with INSERT EXEC I have run into this many times over the years. Here are a few options - none of them are perfect, each has it's pros/cons but should help get you across the finish line nonetheless.
Sample Procs:
USE tempdb
GO
-- Sample Procs
CREATE PROC dbo.proc1 #a INT, #b INT
AS
SELECT x.a, x.b
FROM (VALUES(#a,#b)) AS x(a,b)
CROSS JOIN (VALUES(1),(2),(3)) AS xx(x);
GO
CREATE PROC dbo.proc2 #a INT, #b INT
AS
DECLARE #x TABLE (a INT, b INT);
INSERT #x(a,b)
EXEC dbo.proc1 5,10;
SELECT x.a, x.b FROM #x AS x;
This will fail due to nesting INSERT EXEC:
DECLARE #a INT = 2, #b INT = 4;
DECLARE #t2 TABLE (a INT, b INT);
INSERT #t2(a,b)
EXEC dbo.proc2 5,10;
Option #1: Extract the stored procedure logic and run it directly
Here I'm simply taking the logic from dbo.proc2 and running it ad-hoc
DECLARE #t2 TABLE (a INT, b INT);
DECLARE #a INT = 2, #b INT = 4;
INSERT #t2 (a,b)
-- Logic Extracted right out of dbo.proc1:
SELECT x.a, x.b
FROM (VALUES(#a,#b)) AS x(a,b)
CROSS JOIN (VALUES(1),(2),(3)) AS xx(x);
SELECT t2.* FROM #t2 AS t2;
Option #2 - Extract the proc logic and run it as Dynamic SQL
DECLARE #t2 TABLE (a INT, b INT);
DECLARE #a INT = 2,
#b INT = 4;
DECLARE #SQL NVARCHAR(4000) = N'
SELECT x.a, x.b
FROM (VALUES(#a,#b)) AS x(a,b)
CROSS JOIN (VALUES(1),(2),(3)) AS xx(x);',
#ParmDefinition NVARCHAR(500) = N'#a INT, #b INT';
INSERT #t2
EXEC sys.sp_executesql #SQL, #ParmDefinition, #a=#a, #b=#b;
SELECT t2.* FROM #t2 AS t2; -- validation
Option #3 - option #2 with the proc code directly from metadata
DECLARE #t2 TABLE (a INT, b INT);
DECLARE #a INT = 2,
#b INT = 4;
DECLARE
#SQL NVARCHAR(4000) =
( SELECT SUBSTRING(f.P, CHARINDEX('SELECT',f.P),LEN(f.P))
FROM (VALUES(OBJECT_DEFINITION(OBJECT_ID('proc1')))) AS f(P)),
#ParmDefinition NVARCHAR(500) = N'#a INT, #b INT';
EXEC sys.sp_executesql #SQL, #ParmDefinition, #a=#a, #b=#b;
The downside here is parsing out what I need. I made my example simple with the logic beginning with a SELECT clause, the real world is not as kind. The upside, compared to manually adding the logic, is that your code will be up-to-date. Changes to the proc automatically change your logic (but can also break the code).
Option #4: Global Temp Table
I haven't really tried this but it should work. You could re-write the proc (proc2 in my example) like this:
ALTER PROC dbo.proc2 #a INT, #b INT, #output BIT = 1
AS
IF OBJECT_ID('tempdb..##x','U') IS NOT NULL DROP TABLE ##x;
CREATE TABLE ##x(a INT, b INT);
INSERT ##x(a,b)
EXEC dbo.proc1 5,10;
IF #output = 1
SELECT x.a, x.b FROM ##x AS x;
GO
I am populating a global temp table with the result set then adding an option to display the output or not. When #output = 0 the result-set will live in ##x, which can be referenced like so:
DECLARE #t2 TABLE (a INT, b INT);
EXEC dbo.proc2 5,10,0;
INSERT #t2(a,b)
SELECT * FROM ##x;
SELECT * FROM #t2;
I think I've cracked it. Weird that you spend all afternoon looking at SQL, then the answer comes to you when you are cleaning out a fish tank
I need to split my sproc into two. The first part calls the API, and receives the answer as a JSON array. JSON is basically text, so rather than convert this into a table, I should just return in as an NVARCHAR(MAX) to the calling sproc.
The calling sproc can then call a second sproc to format this JSON into a table format.
As the first sproc isn't returning a table, SQL won't care about the nested Insert...exec, and as the second sproc isn't using a cmdshell, it doesn't need an insert...exec, so it can receive the results into a table
Here is the above example, but with the sproc split into 2...
begin tran
go
create procedure usp_retrieveAPIdata
#inparameter int,
#resultstring varchar(max) output
as
begin
declare #APIcall varchar(200)
--this would normally be an API call, returning a JSON array
set #APICall='echo f1:"foo" & echo f2:"bar" & echo f1:"Hello" & echo f2:"World"'
declare #resulttable table
(outputfield varchar(100),ID int identity)
insert into #resulttable
exec xp_cmdshell #APICall
set #resultstring=''
select #resultstring=#resultstring + isnull(outputfield,'') + '¶' from #resulttable order by ID --using '¶' as a random row delimiter
end
go
create procedure usp_formatdata (#instring varchar(max))
as
begin
print #instring
declare #resulttable table
(outputfield varchar(100),ID int)
insert into #resulttable (outputfield,ID)
select value,idx+1 from dbo.fn_split(#instring,'¶');
declare #formattedtable table
(field1 varchar(100),field2 varchar(100))
declare #rownum int =0
declare #field1 varchar(100)
declare #field2 varchar(100)
declare #currentfield varchar(100)
while exists (select * from #resulttable where ID>#rownum)
begin
set #rownum=#rownum+1
select #currentfield=outputfield from #resulttable where ID=#rownum
if #currentfield like 'f1%'
begin
set #field1=replace(#currentfield,'f1:','')
end
if #currentfield like 'f2%' and #rownum<>1
begin
set #field2=replace(#currentfield,'f2:','')
insert into #formattedtable (field1,field2) values (#field1,#field2)
end
end
select field1,field2 from #formattedtable
end
go
declare #resulttable table (field1 varchar(100),field2 varchar(100))
declare #outstring varchar(max)
exec usp_retrieveAPIdata 110,#resultstring=#outstring output
insert into #resulttable
exec usp_formatdata #outstring
select * from #resulttable
rollback
Many thanks to everyone who took the time to contribute to this thread

How can I return tables with different number of parameters with procedure?

I'm going to create different temp tables depending on the #selection parameter I get, and then I want to return the table I created.
I actually wanted to do it with the function, but I got an error for variable parameter tables. The sql procedur I wrote is as follows:
ALTER PROCEDURE [dbo].[Report]
(#Id BIGINT = 55,
#selection INT)
AS
BEGIN
IF #selection=1
BEGIN
Declare #tep_table table (Id int
,Name varchar(250)
,CreateTime datetime
,UpdateTime datetime
,UpdatedBy varchar(250)
,Deleted bit
)
Insert into #tep_table
Select * from User
END
IF #selection=1
BEGIN
Declare #tep_table2 table (Id int
,CreateTime datetime
,UpdateTime datetime
,UpdatedBy varchar(250)
,Deleted bit
)
Insert into #tep_table2
Select * from Client
END
IF #selection=1
BEGIN
RETURN #tep_table
END
ELSE
BEGIN
RETURN #tep_table2
END
END
I am getting this error:
Must declare the scalar variable "#tep_table"
Personally I would turn this into three procedures to avoid the performance problems faced with multiple execution paths.
Something like this.
ALTER Procedure [dbo].[Report]
(
#Id bigint = 55 --not sure what the point of this parameter is as it wasn't used anywhere in the sample code
, #selection int
) AS
set nocount on;
IF #selection = 1
exec GetUserData;
IF #selection = 2
exec GetClientData;
GO
create procedure GetUserData
AS
set nocount on;
Select * --would prefer to use column names here instead of *
from [User];
GO
create procedure GetClientData
AS
set nocount on;
Select * --would prefer to use column names here instead of *
from Client;
GO

How do I pass a parameter value from one stored procedure to another?

I'm trying to pass the input parameters from one stored procedure to another stored procedure, the value of the parameter will be used to be inserted into a table.
I have two stored procedures, here is the logic for the SP's:
First one -
CREATE PROCEDURE [abc].[SP1](
#ID1 INT
#ID2 INT
#Date VARCHAR(10)
#Value VARCHAR(50)
)
AS
Select into #temp...
EXEC [abc].[SP2] #ID1, #ID2, #Date, #Value
Select...
Second one -
CREATE PROCEDURE [abc].[sp2](
#bID1 INT
#bID2 INT
#bDate VARCHAR(10)
#Value VARCHAR(50)
)
DECLARE #bID1 INT, #bID2 INT, #bDate VARCHAR(10), #Value VARCHAR(50)
--main part that I'm concerned with, getting the parameter values to work
SELECT #bID1, #bID2, #bDate, #Value, x.col1, x.col2
INTO [abc].[tableA]
FROM tableX x
When I try this I receive an error saying that I, "must declare the scalar variable"
It's not how you create procedures in SQL Server. You should do something like this:
CREATE PROCEDURE [SP1]
#ID1 INT
,#ID2 INT
,#Date VARCHAR(10)
,#Value VARCHAR(50)
AS
Select into #temp...
Secondly, when you declared parameteres for the procedure you cannot declare variables with the same names below:
CREATE PROCEDURE [abc].[sp2]
#bID1 INT
,#bID2 INT
,#bDate VARCHAR(10)
,#Value VARCHAR(50)
AS
--main part that I'm concerned with, getting the parameter values to work
SELECT #bID1, #bID2, #bDate, #Value, x.col1, x.col2
INTO [abc].[tableA]
FROM tableX x

WHERE ... IN ... Issue with the SQL Server Stored Procedure

I have to implement SELECT ... FROM ... WHERE .. IN query in my stored procedure.
Below is the code from my stored procedure
ALTER PROCEDURE [dbo].[SP_GetQuestionSetMultiCat]
-- Add the parameters for the stored procedure here
#PIN varchar(50),
#CatIds varchar(50),
#Range int,
#Que_Type varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #qtId as int;
select #qtId = Que_Type_Id from dbo.QuestionType_Tbl where Que_Type=#Que_Type;
-- Insert statements for procedure here
Select Top(#Range)
QId,
Que_Type_Id,
Que_Level_Id,
Que_Category_Id,
Que,
Opt1,
Opt2,
Opt3,
Opt4,
Ans
From
dbo.Que_Tbl
Where
(Que_Category_Id in (cast(#CatIds as varchar)))
and (Que_Type_Id=#qtId)
and (Qid not in (Select Que_Id From dbo.UserQuestion_Mapping where PIN=#PIN and Que_typeID=#qtId))
END
Look at the where condition. The Que_Category_Id is int type. What i want to perform is -
Where Que_Category_Id in (1,2,3,4)
The in values i m passing is a string converted from my C# code.
When I am executing this query like -
exec SP_GetQuestionSetMultiCat '666777','4,5,6',5,'Practice'
it is generating an error -
Conversion failed when converting the varchar value '{4,5,6}' to data type int.
Can anybody help me out how to solve this problem.
Thanks for sharing your valuable time.
1)Conversion failed when converting the varchar value '{4,5,6}' to data type int.
The reason of this error is data type precedence. INT data type has "higher" precedence than VARCHAR data type (16-INT vs. 27-VARCHAR).
So, SQL Server is trying to convert '{4,5,6}' to INT and not vice versa.
2) Instead, I would convert #CatIds to XML and then to a table variable (#IDs) using nodes(...) method:
SET ANSI_WARNINGS ON;
DECLARE #CatIds VARCHAR(50) = '4,5,6';
DECLARE #x XML;
SET #x = '<node>' + REPLACE(#CatIds, ',', '</node> <node>') + '</node>';
DECLARE #IDs TABLE
(
ID INT PRIMARY KEY
);
INSERT #IDs(ID)
SELECT t.c.value('.', 'INT')
FROM #x.nodes('/node') t(c);
--Test
SELECT *
FROM #IDs
3) The next step is to rewrite the query using IN (SELECT ID FROM #IDs) instead of in (cast(#CatIds as varchar)):
SET ANSI_WARNINGS ON;
ALTER PROCEDURE [dbo].[SP_GetQuestionSetMultiCat]
-- Add the parameters for the stored procedure here
#PIN varchar(50),
#CatIds varchar(50),
#Range int,
#Que_Type varchar(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
declare #qtId as int;
select #qtId = Que_Type_Id from dbo.QuestionType_Tbl where Que_Type=#Que_Type;
--Start: New T-SQL code
DECLARE #x XML;
SET #x = '<node>' + REPLACE(#CatIds, ',', '</node> <node>') + '</node>';
DECLARE #IDs TABLE
(
ID INT PRIMARY KEY
);
INSERT #IDs(ID)
SELECT t.c.value('.', 'INT')
FROM #x.nodes('/node') t(c);
--End
-- Insert statements for procedure here
Select Top(#Range)
QId,
Que_Type_Id,
Que_Level_Id,
Que_Category_Id,
Que,
Opt1,
Opt2,
Opt3,
Opt4,
Ans
From
dbo.Que_Tbl
Where
--The search condition is rewritten using IN(subquery)
Que_Category_Id in (SELECT ID FROM #IDs)
and (Que_Type_Id=#qtId)
and (Qid not in (Select Que_Id From dbo.UserQuestion_Mapping where PIN=#PIN and Que_typeID=#qtId))
END
4) Call stored procedure:
exec SP_GetQuestionSetMultiCat '666777','4,5,6',5,'Practice'