I have a stored procedure I don't want to modify. It's rather large and complex, and I don't want to add any more confusion to it.
So what I would like to do is have another store procedure that calls on the big one, and uses the result set to perform further selects / joins etc.
You can insert procedure's result set into table. Like this:
create procedure test
as
begin
select 1
end
go
declare #t table
(
id int
)
insert into #t
exec test
select * from #t -- returns one row
You can use a user-defined function instead:
create function table_func
()
returns table
as
return
(
select top 10 *
from master..msreplication_options
)
Then, to get your result set
select * from table_func()
If you still need to call this as a stored proc in other places, create a stored proc that wraps the user-defined function:
create procedure test_proc
as
select * from test_func();
You can create a user defined function which call the stored procedure you have and use it in other queries.
Related
How would one write a stored procedure that takes as input a table value parameter but that table value parameter consists of row with the columns of an existing table?
I could manually create a TVP that matches the table, populate it with a query pass it into the stored procedure but I can't help but think there is smarter way so I don't have to keep my TVP manually synced with my table.
Basically I want to be able to do
EXEC MYCOOLSPROC #myTVP = resulting rows of 'SELECT * FROM AWESOME_TABLE WHERE ID > 10 AND ID < 20'
First, you need to create the tvp parameter in MYCOOLSPROC as READONLY
CREATE PROCEDURE MYCOOLSPROC
#bTVP MYTVP READONLY
AS
BEGIN
SELECT * FROM #bTVP
END
And this is sample how you use this with MYCOOLSPROC
Declare the TVP variable, insert some values into it
DECLARE #aTVP MYTVP
INSERT INTO #aTVP ( ... ) VALUES ( ... )
OR it can be from the result of another Stored Procedure
INSERT INTO #aTVP
EXEC AnotherStoredProcedure
And then you can pass the #aTVP to MYCOOLSPROC
EXEC MYCOOLSPROC #bTVP = #aTVP
I wrote a procedure that fetches me two columns, who contain the respective symmetric key name and the certificate name, needed to decrypt the passwords in another table. It's working perfectly fine. I get my results and that is working so far.
The "fetching" procedure looks like this:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [fetch_data]
AS
BEGIN
SET NOCOUNT ON;
SELECT [KeyName], [CertName] FROM [Group]
INNER JOIN LT_Groups ON [Group].GroupId = LT_Groups.GroupId
INNER JOIN Verify ON Verify.UserID = LT_Groups.UserId AND VERIFY.USERNAME =
CURRENT_USER
END
GO
EXEC fetch_data
Now I want to write another procedure, that is supposed to work with the results of the first one. I just don't get how I can use the result of my "fetching_data" in another query.
You have to define TempTable and then Store Executed first Stored Procedure result in it Like below:
INSERT INTO #YourTable
EXEC SP
The simplest method is insert-exec, but it does have some issues. If the columns output from the inserted procedure ever change, you will get an error. There are other potential issues as well, see the included reference for more.
insert-exec example:
create table #fetch_data (keyname varchar(32), certname varchar(32));
insert into #fetch_data
exec dbo.fetch_data
Alternatives to insert-exec are using table-valued functions, sharing a temp table, global temp tables, and table-valued parameters.
Reference
How to Share Data between Stored Procedures - Erland Sommarskog
A table-valued function might be more appropriate than an store procedure, in this case.
Table-valued functions can be called from the from clause of other queries, making the values they return readily available.
Example
-- Defines table-valued function.
CREATE FUNCTION fetch_data ()
RETURNS TABLE
AS
RETURN
(
-- Get detiails.
SELECT
[KeyName],
[CertName]
FROM
[Group]
INNER JOIN LT_Groups ON [Group].GroupId = LT_Groups.GroupId
INNER JOIN Verify ON Verify.UserID = LT_Groups.UserId
AND VERIFY.USERNAME = CURRENT_USER
);
GO
-- Using table-valued function.
SELECT
*
FROM
fetch_data()
;
Is it possible, and if so how, to pass data to a table-valued parameter of a stored function using SQL EXEC?
I know how to pass in data from C#. One of my four stored procs using table-valued parameters is not producing the expected results. I'd like to execute my proc from SQL server management studio for debugging purposes, but I am unable to find the correct syntax for doing so, if such a syntax even exists. I haven't found anything relevant in the docs.
My type table:
CREATE TYPE [MyNameSpace].[MyTypeTable] AS TABLE(
//... all my fields
)
My stored proc:
//... bunch of stuff
ALTER PROCEDURE [MyNameSpace].[MyStoredProc]
#MyTypeTableVar MyTypeTable READONLY
AS
BEGIN
//Do a bunch of stuff
//Want to test the stuff in here
END
I have tried:
IF OBJECT_ID('tempdb.dbo.#MyTempTable') IS NOT NULL DROP TABLE tempdb.dbo.#MyTempTable;
select top 0 *
into #MyTempTable
//existing table with structure that matches the table-valued param
from MyNameSpace.MyTable;
//...Long insert statement assigning test data to #MyTempTable
EXECUTE MyNameSpace.MyStoredProc #MyTypeTableVar = #MyTempTable;
which throws:
Operand type clash: nvarchar is incompatible with MyTypeTable
You can't use a temp table - you have to use a table variable:
declare #t [MyNameSpace].[MyTypeTable]
insert into #t (/*columns*/) values
(/* first row */),
(/* second row */)
EXECUTE MyNameSpace.MyStoredProc #MyTypeTableVar = #t;
(You can populate it with either INSERT ... VALUES as shown above or INSERT ... SELECT if you have an existing table containing the data you care about)
Here's a working example:
-- Declare a table parameter
DECLARE #registryUpdates AS typ_KeyValuePairStringTable;
-- Insert one row
INSERT INTO #registryUpdates
VALUES ('Hello', 'World');
-- Call Stored Procedure
EXEC prc_UpdateRegistry #registryUpdates
In SQL Server 2008, is there any way to get the total numbers of Result sets (tables) been populated after an execution of stored procedure.
Lets say I have one stored procedures which internally calls another stored procedure. I want to know that how many result sets it returns that internally called stored procedure.
Can anybody can assist me on this.
e.g.
CREATE PROCEDURE sp_GetReports
(
#reportName AS VARCHAR(50)
)
AS
BEGIN
DECLARE #reportProcName AS VARCHAR(50)
SELECT #reportProcName = ReportProcName
FROM ReportMaster
WHERE ReportName = #reportName;
EXEC (#reportProcName)
/*
* Need to get here, total numbers of Result Sets (tables) retrived.
*/
END
GO
Thanks in advance.
You might be able to:
Get the row count in the stored procedure and retrieve the result as an OUTPUT parameter
Utilize some type of external table (would have to design this)
This gives you the number of rows returned from the stored procedure
USE Northwind
GO
CREATE OR ALTER PROCEDURE dbo.Test (
#rowCnt int OUTPUT
)
AS
SELECT * FROM dbo.Customers
SET #rowCnt = ##ROWCOUNT
GO
DECLARE
#rowCount int
EXEC dbo.Test #rowCount OUTPUT
SELECT #rowCount
What about a workaround?
Create some counter variable in each report.
Every time before SELECT statement, increment it.
Then, return it as the last output in sproc.
Each report should follow this convention.
You can return an output parameter with ##ROWCOUNT from inner procedure and use it in sp_GetReports.
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)