I'm encontering the trouble with sybase 15.0 or 15.5
I 've 2 procedure : a main procedure and a sub procedure.
I call the sub procedure when i 'm in a transaction.
I use temporary table in the sub procedure and can't create it in the transaction.
So I create temporary table in the main procedure and use it in the sub.
Temporary table is only use in sub procedure to update a table.
When i call the main procedure, the table is not update but if i call only the sub procedure (i create temporary table before) the table is update. I don't unerstand where is the trouble.
Somebody have an idea ?
EDIT :
create procedure MainProc
as
create table #tmp1(...)
create table #tmp2(...)
begin
...
begin tran
...
exec SubProc
...
commit
end
--to compile SubProc
create #tmp1(...)
create #tmp2(...)
create procedure SubProc
as
begin
insert into table1
insert into #tmp1
insert into #tmp2
update table1
from #tmp1,#tmp2
end
If i call Exec MainProc table1 is not updated.
But if i create temporary table and call exec SubProc table1 is correctly updated.
Related
I have inherited a database that contains a lot of stored procedures that create a local temporary table, calls a procedure that uses the temp table, and then deletes the temp table. Like this:
CREATE PROCEDURE procSelectFromTable
AS
BEGIN
SELECT *
FROM #myTable
END;
GO
CREATE PROCEDURE procMakeTable
AS
BEGIN
SELECT 1 AS [ID]
,'NestedProcedure' AS [Message]
INTO #myTable;
EXEC procSelectFromTable
DROP TABLE #myTable;
END;
GO
EXEC procMakeTable;
GO
--Clean up
IF OBJECT_ID('tempdb..#myTable') IS NOT NULL
DROP TABLE #myTable;
DROP PROCEDURE procMakeTable;
DROP PROCEDURE procSelectFromTable
I have not seen procedures written in this manner before. Is it safe for me to assume this is ok because the nested procedure will always be called in the same spid and will always be able to access the temp table?
Yes, the nested procedure will have access to the local temp table. This was common use before the introduction of table-valued parameters or when the procedures exist in different databases in the same instance. The procedures are tightly coupled and might be a problem to test the 'child' procedure, but it has the advantage that it can be called from multiple procedures.
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 to run same sp with 100 diff #params once a month which reference data which is hard to get (view runs 2 min, and I need only 2% subset from this view). I want to create some ##temp table so then my sp in all instances will refer to it. How people do this on tsql arena?
Can I include:
If exist then do nothing
in the top of sp code, so it will run only once? and then delete table in separate clean job. or do some ##temp tables, I"m bit new to this . not sure will ## global temp table will work. ALso do I need to go with some special Isolation Level (Serial?) to do this.
Tx for help.
Mario
If the procedure only runs once a month, and view takes its time to run (expensive query) why not just create a table (maybe create some indexes too , to aid the following queries) and then finally create another procedure to populate that table each time you execute your original procedure.
-- Create a holding table
SELECT * INTO Holding_Table
FROM Your_View
WHERE 1 = 2
-- Procedure to populate data into that holding table
CREATE PROCEDURE populate_data
AS
BEGIN
TRUNCATE TABLE Holding_Table
INSERT INTO Holding_Table
SELECT * FROM Your_View
END
Now call this procedure from your existing procedure to populate the data and carry on working with the holding table as usual ...
ALTER PROCEDURE your_existing_Proc
AS
BEGIN
Exec populate_data
..... rest of the procedure definition
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
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)