Calling a stored procedure from another procedure - sql

Using this table variable:
DECLARE #ReturnValue VARCHAR
DECLARE #OUT_MAIN_ERROR VARCHAR
DECLARE #Result VARCHAR(50)
BEGIN
DECLARE #TableVariable TABLE (result VARCHAR(50))
INSERT INTO #TableVariable
EXEC [dbo].[DRIVEPOOL2]
SELECT result
FROM #TableVariable
END
Using temp table:
DECLARE #ReturnValue VARCHAR
DECLARE #OUT_MAIN_ERROR VARCHAR
DECLARE #Result VARCHAR(50)
BEGIN
CREATE TABLE #kola(result VARCHAR(50))
INSERT INTO #kola
EXEC [dbo].[DRIVEPOOL2]
SELECT *
FROM #kola
DROP TABLE #kola
END
I get error:
Msg 8164, Level 16, State 1, Procedure DRIVEPOOL2, Line 45 [Batch Start Line 3]
An INSERT EXEC statement cannot be nested.
I have tried with both temp table and table variable, both are throwing the error that the INSERT EXEC statement can't be nested.
Drive Pool Procedure for Reference - Github

Seems to be duplicate with this thread: INSERT EXEC Statement cannot be nested
This error occurs when calling a stored procedure and inserting the
result of the stored procedure into a table or table variable (INSERT
... EXECUTE) and the stored procedure being called already contains an
INSERT ... EXECUTE statement within its body.
Read more about this error here:http://www.sql-server-helper.com/error-messages/msg-8164.aspx
You can try OPENROWSET to overcome this problem
INSERT INTO #TableVariable ( col1, col2, col3,... )
SELECT SP.*
FROM OPENROWSET('SQLNCLI', '[Your connection string]','EXECUTE [dbo].[DRIVEPOOL2]') AS SP

Related

Inserting into a user-defined table type via a dynamic query in SQL Server?

I have a user-defined table type tyAnalysisNumbers. I need to populate my user defined data type within a stored procedure with a SELECT statement and I am struggling to get that working within my stored procedure.
The following ways I have tried do not work
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM ' + #someTable);
I get this error:
An INSERT EXEC statement cannot be nested
I am unsure how to insert into my custom table via a select statement.
Can anyone help me accomplish this?
An INSERT EXEC statement cannot be nested
Above error is self explanatory. Please look at below scenario:
For example, we have one procedure which inserts data in table type and return result.
CREATE PROCEDURE uspInsertData1
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO #MyTable
EXEC ('SELECT * FROM someTable');
select * from #MyTable
END
Now, let's say we have another procedure which will call above procedure and again insert data in another table.
CREATE PROCEDURE uspInsertData2
AS
BEGIN
DECLARE #MyTable tyAnalysisNumbers;
INSERT INTO sometable
EXEC uspInsertData1
END
Now, if you execute 1st procedure it will work fine but if you execute second procedure you will get this error.
An INSERT EXEC statement cannot be nested.
Because now you have nested EXEC statements.
I suggest to finish your work in single stored procedure if possible.
Try it like this:
DECLARE #MyTable tyAnalysisNumbers;
SELECT * INTO #Temp FROM #MyTable;
DECLARE #tblName AS SYSNAME = (SELECT name FROM sys.tables WHERE name = #someTable);
EXEC ('INSERT INTO #Temp SELECT * FROM ' + #tblName);
This also addresses the SQL Injection problem.

How can I assign an exec result to multiple sql variables?

I got the returned data after executing a stored procedure named [s_sspCallSharePointWebService] in SSMS
DECLARE #sWebAddr AS NVARCHAR(MAX),
#bAPISuccess AS NVARCHAR(10),
#objSharePointXML AS XML
SET #sWebAddr = 'http://...'
EXEC [s_sspCallSharePointWebService] #sWebAddr, #bAPISuccess OUTPUT, #objSharePointXML OUTPUT
I was wondering how do I save
the data in variables instead of returning a table below.
---------------------------------------
| (No column name) | (No column name) |
---------------------------------------
| True | <XMLRoot>.... |
---------------------------------------
Additionally, I cannot insert the data into a temp table here because I had the result of EXEC sp_OAGetProperty #objecttoken, 'responseText' in [s_sspCallSharePointWebService], and then already inserted the response text into a temp table.
That would cause an error:
An INSERT EXEC statement cannot be nested
It is very ugly (for me), but this can be done using temporary tables. The temporary table is visible to all routines in the current scope.
So, you can have nesting like this:
EXEC SP1
...
EXEC SP2
...
EXEC SP3
...
and let's say EXEC SP2 is returning a row set executing a SELECT statement. So, the question is how to materialized it?
CREATE PROCEDURE dbo.SP1
AS
BEGIN;
SELECT 'SP1' AS [Caller];
EXEC dbo.SP2;
END;
GO
CREATE PROCEDURE dbo.SP2
AS
BEGIN;
SELECT 'SP2' AS [Caller];
INSERT INTO #TEST
SELECT 1;
END;
GO
CREATE TABLE #TEST
(
[ID] INT
);
EXEC dbo.SP1;
SELECT *
FROM #TEST;
The idea is to create the temporary table in the outer scope and the procedure to be sure that this table is already created and populate it. Then, use the table in the initial caller.
It's ugly for me, because if this table is not defined the routine will cause an error:
Msg 208, Level 16, State 0, Procedure dbo.SP2, Line 8 [Batch Start
Line 0] Invalid object name '#TEST'.
and it can be difficult to debug in some cases.
Instead of doing that, you can just use a table variable, and then SELECT from it to assign. Here's an example with a simple proc that returns a single row:
USE tempdb;
GO
CREATE OR ALTER PROC dbo.ReturnsOneRow
AS
BEGIN
SELECT 1 AS FirstColumn, 'Hello' AS SecondColumn, 4 AS ThirdColumn;
END;
GO
EXEC dbo.ReturnsOneRow;
GO
DECLARE #FirstColumn int;
DECLARE #SecondColumn varchar(20);
DECLARE #ThirdColumn int;
DECLARE #Row TABLE
(
FirstColumn int,
SecondColumn varchar(20),
ThirdColumn int
);
INSERT #Row
(
FirstColumn, SecondColumn, ThirdColumn
)
EXEC dbo.ReturnsOneRow;
SELECT TOP(1) #FirstColumn = r.FirstColumn,
#SecondColumn = r.SecondColumn,
#ThirdColumn = r.ThirdColumn
FROM #Row AS r;
-- Check the values
SELECT #FirstColumn, #SecondColumn, #ThirdColumn;
The table variable will be way better than a temp table in this situation, and you don't have issues with its visibility elsewhere, or having to clean it up (it's gone at the end of the batch).

Calling stored procedure from other stored procedure

This is stored procedure #1:
ALTER PROCEDURE [dbo].[sp1]
AS
BEGIN
DECLARE #test varchar(255)
exec #test = dbo.sp2
SET NOCOUNT ON;
SELECT
CMS_ORG.description, #test
FROM
CMS_ORG
END
This is stored procedure #2:
ALTER PROCEDURE [dbo].[sp2]
AS
BEGIN
SET NOCOUNT ON;
SELECT
CMS_MAS.description + '' + CONVERT(varchar(50),
CAST(CMS_ORG.amount AS money), 1)
FROM
CMS_ORG
INNER JOIN
CMS_MAS = CMS_ORG.GUID = CMS_MAS.GUID
END
The problem is here is I was not able to execute #test in stored procedure #1 by calling the stored procedure #2. When I execute sp1, I got a null values instead but when I execute the query of sp2 in sp1, I got a correct value. May I know what is the possible solution or similar examples which can solve the issue?
Your stored proc sp2 outputs the result of a SELECT, but like all stored procs, it returns an integer using the return statement. You don't have a return statement, so Sql Server generates one for you: return 0. The purpose of the return code is to give feedback on whether it ran as expected. By convention, a return code of 0 means no errors.
This shows the difference between the return code and the output of a stored proc. Create a temp table #output to capture the rows of the SELECT that the stored proc outputs.
DECLARE #return_code int
-- capture the output of the stored proc sp2 in a temp table
create table #output( column_data varchar(max) )
insert #output( column_data )
exec #return_code = dbo.sp2 -- returns 0 because you have no RETURN statement
-- extract column_data from #output into variable #test
-- if there is more than one row in #output, it will take the last one
DECLARE #test varchar(255)
select #test = column_data from #output
Create a table variable & Use it like this :
create proc test55
as
select 55
declare #test table (Value Varchar(255))
insert into #test
exec test55
Select * from #test
Your sp2 stored procedure will return table, not varchar(255).
If you want to get a varchar(255) from sp2 you should be using function.
You can view in my example:
Define a function:
CREATE FUNCTION dbo.function1()
RETURNS varchar(255)
WITH EXECUTE AS CALLER
AS
BEGIN
DECLARE #returnVal varchar(255);
SET #returnVal = (SELECT top 1 [ProductName]
FROM [dbo].[Products])
RETURN(#returnVal);
END;
And alter SP1 like this:
ALTER PROCEDURE [dbo].[sp1]
#SMonth As Integer,
#SYear As Integer
AS
BEGIN
DECLARE #test varchar(255)
set #test = dbo.function1()
SET NOCOUNT ON;
SELECT [ProductId], #test
FROM [LearningKO].[dbo].[Products]
END

How to use parameters in sql queries (sp_executesql not working as per requirement)

I have used temporary tables plus temporary variables..
Now when my sql queries are having both temporary variables and table, i got to know sp_executesql not working because we can't use temporary tables in it
and standard execution won't take the variable parameters.
So it will be very helpfull if anyone can help me out with some other solution for it?
This is a sample code :
create procedure tryit
as begin
declare #temp as Table_Type;
declare #ghdhj as nvarchar(50)
set #ghdhj='TBVHTempSelectionTable';
declare #sqlstatement nvarchar(max);
set #sqlstatement=N'insert into #temp select * from '+#ghdhj+';';
exec sp_executesql #sqlstatement;
--,#temp='finalResultTable',#ghdhj='TBVHTempSelectionTable'
select * from #temp;
end
go
exec tryit
Create temporary table and then execute sp_executesql
If you create the temporary table first you should be able to access it in sp_executesql if you specify it explicitly
select *
into #peter
from (values (10), (10)) p(a);
exec sp_executesql N'insert into tempdb..#peter values (20), (20)';
select * from #peter;
-- Result
A
10
10
20
20
sp_executesql can accept table valued parameters, so you can pass a table variable to sp_executesql.
First, you need a table type defined on your database. You create table types using CREATE TYPE statement. For example:
CREATE TYPE dbo.CategoryTableType AS TABLE
(
CategoryID int,
CategoryName nvarchar(50)
)
GO
Once you have the table type you can pass table variables of that type to sp_executesql. For example:
DECLARE #Categories CategoryTableType
INSERT INTO #Categories
VALUES (1, 'Beverages'), (2, 'Confections')
EXEC dbo.sp_executesql
N'SELECT * FROM #Categories',
N'#Categories CategoryTableType READONLY',
#Categories
sp_executesql cannot access variables of any kind declared outside the sql statement passed to sp_executesql.
However sp_executesql can access to temporary tables created in the calling scope stack. For example:
CREATE TABLE #Categories (
CategoryID int,
CategoryName nvarchar(50)
)
INSERT INTO #Categories VALUES
(1, 'Beverages'), (2, 'Confections')
EXEC dbo.sp_executesql N'SELECT * FROM #Categories'
DROP TABLE #Categories
On the other hand the calling scope cannot access to temporary tables created in the sql statement passed to sp_executesql. For example the following code will fail with Msg 208, Level 16, State 0, Invalid object name '#Categories'.
EXEC dbo.sp_executesql N'
CREATE TABLE #Categories (
CategoryID int,
CategoryName nvarchar(50)
)
INSERT INTO #Categories VALUES
(1, ''Beverages''), (2, ''Confections'')'
SELECT * FROM #Categories
Also, the calling scope cannot access to any variable declared inside the sql statement passed to sp_executesql

INSERT EXEC Statement cannot be nested [duplicate]

This question already has answers here:
Errors: "INSERT EXEC statement cannot be nested." and "Cannot use the ROLLBACK statement within an INSERT-EXEC statement." How to solve this?
(13 answers)
Closed 8 years ago.
I have three Procedures MainProcedure,Procedure1,Procedure2
1) In Procedure1 I just have a select statement ,
2) In Procedure2 am calling the Procedure1 and inserting the Output to a #table
3) In the main Procedure I am calling the Procedure2 and iam trying to insert the Output to a #table which throws an error
Msg 8164, Level 16, State 1, Procedure Procedure2, Line 10
An INSERT EXEC statement cannot be nested.
I can resolve this using Openrowset where I need to use specify Server Name ,is there any other way to solve this by not specifying the servername details
please find the sample procedure for reference
Create Proc Procedure1
As
Begin
Select 'Arun' Name, 'Pollachi' Place
Union
Select 'Vedaraj' Name, 'Devakottai' Place
End
Go
Create Proc Procedure2
As
Begin
Create Table #Table1
(
Name Varchar(50), Place Varchar(50)
)
INSERT #Table1
Exec Procedure1
SELECT 'Procedure2' [Source], * FROM #Table1
DROP TABLE #Table1
End
Go
Create Proc MainProcedure
As
Begin
Create Table #Table1
(
[Source] Varchar(50), Name Varchar(50), Place Varchar(50)
)
INSERT #Table1
Exec Procedure2
select * from #Table1
DROP TABLE #Table1
End
Go
can any one change my main procedure and make it to get executed
Thanks!!
Like you said, openrowset will work, but other than that the only ways I can think of would be:
Change both proc 1 and proc 2 to table based functions
Change proc 2 to a CLR and put all logic in there
Pass the tables around as table valued parameters
There's more info about the reasoning for this here:
https://connect.microsoft.com/SQLServer/feedback/details/294571/improve-insert-exec
http://dataeducation.com/revisiting-isnull-coalesce-and-the-perils-of-micro-optimization/