I have 2 store procedure :
The first one to create #TempTable
CREATE PROCEDURE CreateTempTable
AS
BEGIN
IF OBJECT_ID('tempdb..#TempTable') IS NOT NULL
BEGIN
DROP TABLE #TempTable;
END
CREATE TABLE #TempTable(
Value real NOT NULL
END
The second one to insert data in my #TempTable
CREATE PROCEDURE InsertData
#Value real
AS
BEGIN
INSERT #TempTable (Value) VALUES #Value
END
When I call these procedure I have an error :
exec CreateTempTable
exec InsertData" 1
go
Name '#TempTable' not valid in InsertData
Can you help me ?
A temp table created inside a sproc is automatically dropped after the sproc ends.
You have a few choices:
Create the temp table outside of the sproc as a standalone query. Then it will be dropped after the connection closes
Create a sproc that first creates the temp table and then calls the other sprocs
Use a global temp table (careful - concurrency issues can crop up with this)
I guess the problem here is that you are creating a local temporary table, that cannot be accessed outside CreateTempTable. You should create a global temporary table, by using ## instead of #.
Edit Yep, that's it. Here is your fixed script:
CREATE PROCEDURE CreateTempTable
AS
BEGIN
IF OBJECT_ID('tempdb..##TempTable') IS NOT NULL
BEGIN
DROP TABLE ##TempTable;
END
CREATE TABLE ##TempTable(
Value real NOT NULL
)
END
GO
CREATE PROCEDURE InsertData
#Value real
AS
BEGIN
INSERT ##TempTable (Value) VALUES (#Value)
END
GO
exec CreateTempTable
exec InsertData 1
go
Related
I have the following structure of stored procedures:
exec A -> exec B -> exec C -> exec D
where stored procedure A calls stored procedure B, B calls C and C calls D.
I need a special behavior to happen in stored procedure D based on a condition that is determined in stored procedure A. Of course one option is to pass param from A to B, then from B to C, then from C to D, but I was wondering if I can simply just create a temp table prior to executing A, then when I am in stored procedure D I can just check if temp table exists and perform my logic based on that.Finally in the line right after exec A, I will drop the temp table
EDIT: I am aware that if proc D is called from a different procedure the condition will be treated as not exists. Also I am aware of temp table name can clash with another temp table with the same name. Other than that...
Is there any unwanted side effects to doing the later solution?
The temp tables or (#tables) should have the lifespan of the session. In the case you describe you should be able to create the #table in PROC A and reference it on PROC D without any special considerations.
Please note that if you take this approach you are creating a direct dependency between PROC D and PROC A, since now you have to call PROC A to create the Temp table you are using on PROC D. If you are OK with this then go ahead.
I usually use a persistent [Params] table. I have procedure:
CREATE OR ALTER PROCEDURE SetParam #name VarChar(20), #value VarChar(50) AS BEGIN
-- I don't like MERGE, but it could be used here as well.
BEGIN TRY
INSERT INTO [Params] ([Name], [Value])
VALUES (#name, #value)
END TRY
BEGIN CATCH
UPDATE [Params] SET [Value] = #Value
WHERE [Name] = #name
END CATCH
END
GO
CREATE OR ALTER PROCEDURE GetParam #name VarChar(20), #value VarChar(50) OutPut AS BEGIN
SET #value = NULL
-- Try - Catch could be here as well
SELECT #value FROM [Params] WHERE [Name]=#name
END
GO
-- In A
EXEC SetParam 'Param','Value'
-- In D
DECLARE #ParamValue Int
EXEC GetParam 'ParamName', #ParamValue OutPut
I have 2 procedures proc_Data, proc_FetchData.
I'm calling proc_Data from within proc_FetchData. proc_Data returns 2 tables. I want to insert only the first table into a temp table in my second procedure and use it further.
The problem is I cannot change proc_Data in any way as this is a very old procedure used in various parts of our application.
Sample code for reference
create procedure proc_Data
As
Begin
select 'Apples'
select 'Oranges','Grapes'
end
create procedure proc_FetchData
As
Begin
create table #temp(Data varchar(30))
insert into #temp
exec Test_proc
select * from #temp
end
I'm using SQL Server 2014 - is there any way to achieve this? Thanks in advance.
You cant do it that way, you can split your first SP into 2 and call it in your second SP, like,
create procedure proc_Data1
As
Begin
select 'Apples'
end
GO
create procedure proc_Data2
As
Begin
select 'Oranges','Grapes'
end
GO
ALTER procedure proc_FetchData
As
Begin
create table #temp(
Data varchar(30)
)
insert into #temp
exec proc_Data1
select * from #temp
end
To insert only the first table you can use OPENROWSET.
create procedure proc_FetchData
As
Begin
declare #userData TABLE(Data NVARCHAR(30))
INSERT INTO #userData
SELECT * FROMOPENROWSET('SQLNCLI','Server=[server];Trusted_Connection=yes;','EXEC [database name].dbo.proc_Data')
select * from #userData
end
If you need to access all resultsets you will need to use SQLCLR proc: https://social.msdn.microsoft.com/Forums/sqlserver/en-US/da5328a7-5dab-44b3-b2b1-4a8d6d7798b2/insert-into-table-one-or-multiple-result-sets-from-stored-procedure?forum=transactsql
I suggest you add a new input parameter with a default value to your procedure and return different datasets depended on its value.
ALTER procedure proc_Data
#Mode INT = 0
As
Begin
IF #Mode = 0 BEGIN
select 'Apples'
select 'Oranges','Grapes'
END
ELSE BEGIN
select 'Apples'
END
end
go
ALTER procedure proc_FetchData
As
Begin
create table #temp(Data varchar(30))
insert into #temp
exec proc_Data #Mode = 1
select * from #temp
end
After doing so, you will be able to use your proc_Data in any old queries without changes, whereas its output will be different with different #Mode values if you need.
I have a transaction that calls a stored procedure which creates a temp table. I need to be able to access this temp table outside of the stored procedure after it has been ran. Note: for what I am trying to do, I cannot use global temp tables.
Example:
Here is an example of the stored procedure:
CREATE PROCEDURE [dbo].[GetChangeID]()
AS
BEGIN
IF OBJECT_ID('tempdb..#CurrentChangeID') IS NOT NULL
DROP TABLE #CurrentChangeID
SELECT '00000000-0000-0000-0000-000000000000' AS ChangeID INTO #CurrentChangeID
END
GO
Here is an example of the transaction:
BEGIN TRANSACTION
DECLARE #changeID uniqueidentifier
EXEC dbo.GetChangeID
DECLARE #test uniqueidentifier
SET #test = (SELECT ChangeID FROM #CurrentChangeID)
COMMIT TRANSACTION
GO
The issue is that it cannot find a table named #CurrentChangeID.
How can I make it to where it can see this table without declaring it as a global temp table such as ##CurrentChangeID?
------UPDATE------
So let me give more context to my question because that was just a simplified example. So what I am ultimately trying to do is this: 1. Begin Transaction 2. Call stored procedure that generates the GUID 3. Then update row in a given view that has a trigger. 4. Within that trigger get the GUID that was generated within the sp. 5. Commit.
First of all you can't get access to local temp table defined in SP outside stored procedure. It will always be out of scope.
Second you probalbly don't even need temp table. In your example:
SET #test = (SELECT ChangeID FROM #CurrentChangeID)
it looks like you want only one value.
I propose to use output parameter.
CREATE PROCEDURE [dbo].[GetChangeID](
#test UNIQUEIDENTIFIER OUTPUT
)
AS
BEGIN
-- ...
SET #test = '00000000-0000-0000-0000-000000000000';
END;
And call:
DECLARE #changeID uniqueidentifier
EXEC dbo.GetChangeID #chaneId OUTPUT;
SELECT #changeId;
Thank you lad2025 and Dan Guzman for your input. The way I was originally trying to do this was definitely incorrect.
I did, however, figure out a way to accomplish this task.
Modified Stored Procedure:
CREATE PROCEDURE [dbo].[GetChangeID]()
AS
BEGIN
DECLARE #ChangeID uniqueidentifier
...
Code that generates the uniqueidentifier, #ChangeID.
...
--This can be seen within the context of this batch.
SET CONTEXT_INFO #ChangeID
END
GO
Then anywhere within this transaction that you would like to access the changeID, you just have to use the following query:
SELECT CONTEXT_INFO as changeID
FROM sys.dm_exec_requests
WHERE session_id = ##SPID AND request_id = CURRENT_REQUEST_ID()
I have a conceptual way I'd like to code a set of related functions and stored procedures. I'm hoping to get a little feedback on whether or not that way is doable.
In a stored procedure, I'd like to assign the values of a table-valued function to a temporary table, then pass that table to another stored procedure...
Can I do this without creating table types?
A quick sample of the #temp table solution:
CREATE PROCEDURE dbo.B
AS
BEGIN
SET NOCOUNT ON;
SELECT * FROM #foo;
END
GO
CREATE PROCEDURE dbo.A
AS
BEGIN
SET NOCOUNT ON;
SELECT TOP 1 * INTO #foo FROM sys.objects;
EXEC dbo.B;
DROP TABLE #foo;
END
GO
EXEC dbo.A;
DROP PROCEDURE dbo.A, dbo.B;
I have 2 stored procedures usp_SP1 and usp_SP2. Both of them make use of insert into #tt exec sp_somesp. I wanted to create a 3rd stored procedure which will decide which stored proc to call. Something like:
create proc usp_Decision
(
#value int
)
as
begin
if (#value = 1)
exec usp_SP1 -- this proc already has insert into #tt exec usp_somestoredproc
else
exec usp_SP2 -- this proc too has insert into #tt exec usp_somestoredproc
end
Later, I realized I needed some structure defined for the return value from usp_Decision so that I can populate the SSRS dataset field. So here is what I tried:
Within usp_Decision created a temp table and tried to do "insert into #tt exec usp_SP1". This didn't work out. error "insert exec cannot be nested"
Within usp_Decision tried passing table variable to each of the stored proc and update the table within the stored procs and do "select * from ". That didn't work out as well. Table variable passed as parameter cannot be modified within the stored proc.
Please suggest what can be done.
Can you modify usp_SP1 and usp_SP2?
If so, in usp_Decision, create a local temporary table with the proper schema to insert the results:
create table #results (....)
Then, in the called procedure, test for the existence of this temporary table. If it exists, insert into the temporary table. If not, return the result set as usual. This helps preserve existing behavior, if the nested procedures are called from elsewhere.
if object_id('tempdb..#results') is not null begin
insert #results (....)
select .....
end
else begin
select ....
end
When control returns to the calling procedure, #results will have been populated by the nested proc, whichever one was called.
If the result sets don't share the same schema, you may need to create two temporary tables in usp_Decision.
Have you had a look at table-valued user-defined functions (either inline or multi-statement)? Similar to HLGEM's suggestion, this will return a set which you may not have to insert any where.
Not a fan of global temp tables in any event (other processes can read these table and may interfere with the data in them).
Why not have each proc use a local temp table and select * from that table as the last step.
Then you can insert into a local temp table in the calling proc.
esimple example
create proc usp_mytest1
as
select top 1 id into #test1
from MYDATABASE..MYTABLE (nolock)
select * from #test1
go
--drop table #test
create proc usp_mytest2
as
select top 10 MYTABLE_id into #test2
from MYDATABASE..MYTABLE (nolock)
select * from #test2
go
create proc usp_mytest3 (#myvalue int)
as
create table #test3 (MYTABLE_id int)
if #myvalue = 1
Begin
insert #test3
exec ap2work..usp_mytest1
end
else
begin
insert #test3
exec ap2work..usp_mytest2
end
select * from #test3
go
exec ap2work..usp_mytest3 1
exec ap2work..usp_mytest3 0
See this blog article for one wortkaround (uses OPENROWSET to essentially create a loopback connection on which one of the INSERT EXEC calls happens)