i have a stored proc A that contains a stored proc B.
stored proc B does an insert and returns a row of information.
is there a way to access that info in stored proc A?
You can execute the stored procedure and selected it into a temp table.
Create #table ()....
INSERT INTO #table EXEC your_procedure
The only time when it really becomes difficult (and maybe impossible, I've never seen it done) is when the stored procedure returns multiple recordsets (not multiple records) and the recordsets have different fields.
EDIT:
You can can also use a table variable (DECLARE #my_table TABLE()) to do the same thing. In your situation you'll want to try both and see which is better.
http://www.sql-server-performance.com/2007/temp-tables-vs-variables/
You could create a temp table and then insert-exec from the inner procedure call.
Share Data
Scroll down to the Insert-Exec section.
I will recommend you to create a Table variable and insert the row information into it
EDIT:
Please note that it will be useful if not under Transaction and not joining it with other tables and just acting as a intermediate for containing row information as you just said in the query.
Related
I have a certain stored procedure written years ago. It uses a table variable. Inside the code it's doing:
declare #OpportunityVS3 as SF_OpportunityMerge
insert #TableVariable select * from /*...*/
This is inside a job that runs every five minutes. There used to be no issues in the past because the select used to collect around 10 to 1000 records… But now sometimes the select is trying to insert a million records.
Given this issue, I think I am forced to change the #TableVariable to a #TempTable. What do you think? Do I have any other option?
At the end of the SP, it’s passing the Variable to another SP:
exec [dbo].[SF_MergeOpportunity] #OpportunityVS3, #LastUpdateDate
I guess I will have to write it all in the same stored procedure, because temporary tables cannot be passed, right?
Below is the definition of the #TableVariable that is being used and the code I would have to change:
declare #OpportunityVS3 as SF_OpportunityMerge
insert #OpportunityVS3 select Opportunity_id, Salesforce_id, AccountId, Age__c,
-- (continues)
merge [BU2].[dbo].[Salesforce_Opportunity] as TARGET
using ( select Opportunity_id,
Salesforce_id,
AccountId,
Age__c,
Amount,
Bill99Amount__c,
BJ_Marketing__c
-- (continues)
from #OpportunityVS3 ) as SOURCE on (TARGET.Opportunity_id = SOURCE.Opportunity_id)
exec [dbo].[SF_MergeOpportunity] #OpportunityVS3, #LastUpdateDate
[![enter image description here][1]][1]
[![enter image description here][2]][2]
What you can try without changing the way you work:
Force the compiler to take cardinalities of TABLE variables into account by specifying OPTION(RECOMPILE) in queries using the TABLE variables
Supply a suitable UNIQUE INDEX or PRIMARY KEY for the TABLE variable
A downside of TABLE variables is that there are no statistics associated with them. The SQL compiler will produce better execution plans when it can take statistics into account. Therefore you can improve performance considerably when you switch to temporary tables because these do have statistics.
When you switch to temporary tables, you would no longer pass a TABLE variable to your stored procedure anymore. Your stored procedure would then be written using a temporary table that it knows exists beforehand - ie was created before the stored procedure is executed.
You would write your stored procedure as though the temporary table were an ordinary table. When you write the stored procedure using a temporary table, SQL Server management studio will underline certain parts in red so it appears as though there are errors in your stored procedure. But if the syntax is correct, creating/altering the stored procedure will work just fine.
Read this excellent essay on the differences between TABLE variables and temporary tables, to see how usage may impact performance. Especially topics No column statistics and Indexes.
I have stored procedure which returns multiple data sets and I need to create tables based on that data sets to get data types. Found this code
SELECT *
INTO newTable
FROM OPENROWSET ('SQLNCLI', 'Server=localhost;Trusted_Connection=yes;',
'EXEC ISS.dbo.sp')
but it works only for first result set and I need tables for all results
As far as I know, cleaner way of using stored procedure output to populate data to a table is a much required solution. There are many ways including the ones you have shown above, but every technique has its own plus and minus.
The solution I have used is create global temporary table
I don't know if it suits for our need.
Once OpenTable is created you can do this over and over again:
Insert into OpenTable
Exec dbo.proc55
CREATE PROCEDURE [test].[proc]
#ConfiguredContentId int,
#NumberOfGames int
AS
BEGIN
SET NOCOUNT ON
RETURN
#WunNumbers TABLE (WinNumb int)
INSERT INTO #WunNumbers (WinNumb)
SELECT TOP (#NumberOfGames) WinningNumber
FROM [Game].[Game] g
JOIN [Game].[RouletteResult] AS rr ON g.[Id] = rr.[gameId]
WHERE g.[ConfiguredContentId] = #ConfiguredContentId
ORDER BY g.[Stoptime] DESC
SELECT WinNumb, COUNT (WinNumb) AS "Count"
FROM #WunNumbers wn
GROUP BY wn.[WinNumb]
END
GO
This stored procedure returns values from first select statement, but I would like to have values from second select statement to be returned. Table #WunNumbers is a temporary table.
Any ideas???
Take a look at this code,
CREATE PROCEDURE Test
AS
DECLARE #tab table (no int, name varchar(30))
insert #tab select eno,ename from emp
select * from #tab
RETURN
What version of SQL Server are you using? In SQL Server 2008 you can use Table Parameters and Table Types.
An alternative approach is to return a table variable from a user defined function but I am not a big fan of this method.
You can find an example here
A temp table can be created in the caller and then populated from the called SP.
create table #GetValuesOutputTable(
...
);
exec GetValues; -- populates #GetValuesOutputTable
select * from #GetValuesOutputTable;
Some advantages of this approach over the "insert exec" is that it can be nested and that it can be used as input or output.
Some disadvantages are that the "argument" is not public, the table creation exists within each caller, and that the name of the table could collide with other temp objects. It helps when the temp table name closely matches the SP name and follows some convention.
Taking it a bit farther, for output only temp tables, the insert-exec approach and the temp table approach can be supported simultaneously by the called SP. This doesn't help too much for chaining SP's because the table still need to be defined in the caller but can help to simplify testing from the cmd line or when calling externally.
-- The "called" SP
declare
#returnAsSelect bit = 0;
if object_id('tempdb..#GetValuesOutputTable') is null
begin
set #returnAsSelect = 1;
create table #GetValuesOutputTable(
...
);
end
-- populate the table
if #returnAsSelect = 1
select * from #GetValuesOutputTable;
YES YOU CAN.
In your stored procedure, you fill the table #tbRetour.
At the very end of your stored procedure, you write:
SELECT * FROM #tbRetour
To execute the stored procedure, you write:
USE [...]
GO
DECLARE #return_value int
EXEC #return_value = [dbo].[getEnregistrementWithDetails]
#id_enregistrement_entete = '(guid)'
GO
The return type of a procedure is int.
You can also return result sets (as your code currently does) (okay, you can also send messages, which are strings)
Those are the only "returns" you can make. Whilst you can add table-valued parameters to a procedure (see BOL), they're input only.
Edit:
(Or as another poster mentioned, you could also use a Table Valued Function, rather than a procedure)
First create a real, permanent table as a template that has the required layout for the returned temporary table, using a naming convention that identifies it as a template and links it symbolically to the SP, eg tmp_SPName_Output. This table will never contain any data.
In the SP, use INSERT to load data into a temp table following the same naming convention, e.g. #SPName_Output which is assumed to exist. You can test for its existence and return an error if it does not.
Before calling the sp use this simple select to create the temp table:
SELECT TOP(0) * INTO #SPName_Output FROM tmp_SPName_Output;
EXEC SPName;
-- Now process records in #SPName_Output;
This has these distinct advantages:
The temp table is local to the current session, unlike ##, so will not clash with concurrent calls to the SP from
different sessions. It is also dropped automatically when out of scope.
The template table is maintained alongside the SP, so if changes are
made to the output (new columns added, for example) then pre-existing
callers of the SP do not break. The caller does not need to be changed.
You can define any number of output tables with different naming for
one SP and fill them all. You can also define alternative outputs
with different naming and have the SP check the existence of the temp
tables to see which need to be filled.
Similarly, if major changes are made but you want to keep backwards
compatibility, you can have a new template table and naming for the later
version but still support the earlier version by checking which temp
table the caller has created.
Here's a issue I have with a stored procedure (using SQL Server 2005), inside this stored procedure it calls another stored procedure putting the data into a temp table.
INSERT INTO #tmpTable (Column1, Column2, Column3)
EXEC psp_rptInsideStoredprocedure 2
This inside stored procedure has a mode parameter that determines which columns get passed out. In this mode (Mode2) only 3 columns get passed out, when this inside stored procedure is used for another report (Mode1) 4 columns gets passed out. Sometimes the parent stored procedure complains about trying to insert the 4 column and sometimes not.
I know it's always passing in mode 2 but it's like SQL Server knows that sometimes this stored procedure has passed back 4 columns.
Any thoughts on a solution?
Thanks
Don
Make the child procedure always return the same number and type of columns, use NULL if necessary. If the results are so different for the two versions, that you can't combine them like this, you should consider making two different procedures.
I'm just guessing at your procedure, but you could create a #ResultSet temp table and populate it based on your type parameter, but always return all columns, etc. If you are returning lots of rows this becomes bad, as the temp table is overhead. in that case, just make sure your result sets return the same number of columns:
IF #version=1
BEGIN
SELECT col1, col2, NULL FROM ... WHERE ...
END
ELSE
BEGIN
SELECT col1, col2, col3 FROM ... WHERE ...
END
Then when both parents call it, accept all the columns, but they can ignore what they don't need.
Daisy chaining stored procedures is generally not a great idea. I would remove the call to the sproc and type out the t-sql for exactly what you need. If your really set on calling another sproc. Make a new sproc that does exactly what you need for this one situation.
It's all about the Single Responsibility Principle
I have a Stored Procedure that rolls-back a series of operations. I want to call this from within another SP.
The problem is that the inner SP returns a record set with a single value that indicates the degree of success.
This approach worked well and has some advantages in our context, but in retrospect, I would have done it the conventional way with a Return value or an Output parameter.
I could always change this SP to use this approach and modify the calling code, but a) I don't want to dabble with any more code than I have to, and b) at an intellectual level, I'm curious to see what alternative solution there may be, if any.
How (if at all) can I call this SP and determine the value of the singleton recordset returned?
Thanks
A stored procedure returns a record set like any other, so you can actually do this:
INSERT INTO MyTable (
MyValue
)
EXEC dbo.MyStoredProcedure
The EXEC takes the place of a SELECT statement. To get the value, just SELECT from the table you inserted into. Typically, this would be a temp table.
The other option is to convert the stored procedure that returns a recordset into a function that returns a table.
Ant's approach is probably best if you want to minimize the changes to your system.
Normally you would use a temporary table for that approach since you can't use an exec statement to insert into a table variable.
Here's a variation which will work well if you need to use this for MULTIPLE recordsets.
CREATE TABLE #outsidetable (...)
exec spInsideProcedure
SELECT * FROM #outsidetable
inside spInsideProcedure
INSERT INTO #outsidetable SELECT <blah blah blah>
I tried Ant's approach and it worked a treat:
Declare #Success tinyint
Declare #Response Table (Success int)
Insert into #Response(Success)
Exec Fix_RollbackReturn 12345, 15
Select #Success=Success from #Response
As you can see I used a Table Variable rather than a temporary table because slightly more efficient than a temporary table.
Thanks for all your help guys.
EDIT: It appears that Dave was right after all. That is, my Exec-into-Table-variable approach worked on my SQL2005 development machine, but when moved to the Live (SQL2000) machine it objected, so I had to change to the temporary table approach.
It's a little annoying, especially since in a couple of weeks we are upgrading to SQL2005 across the board(!).