21

I have two stored procedures, one of which returns a list of payments, while the other returns a summary of those payments, grouped by currency. Right now, I have a duplicated query: the main query of the stored procedure that returns the list of payments is a subquery of the stored procedure that returns the summary of payments by currency. I would like to eliminate this duplicity by making the stored procedure that returns the list of payments a subquery of the stored procedure that returns the summary of payments by currency. Is that possible in SQL Server 2008?

isekaijin
  • 19,076
  • 18
  • 85
  • 153

5 Answers5

21

You are better off converting the first proc into a TABLE-VALUED function. If it involves multiple statements, you need to first define the return table structure and populate it.

Sample:

CREATE proc getRecords @t char(1)
as
set nocouut on;
-- other statements --
-- final select
select * from master..spt_values where type = @t
GO

-- becomes --

CREATE FUNCTION fn_getRecords(@t char(1))
returns @output table(
    name sysname,
    number int,
    type char(1),
    low int,
    high int,
    status int) as
begin
-- other statements --
-- final select
insert @output
select * from master..spt_values where type = @t
return
end;

However, if it is a straight select (or can be written as a single statement), then you can use the INLINE tvf form, which is highly optimized

CREATE FUNCTION fn2_getRecords(@t char(1))
returns table as return
-- **NO** other statements; single statement table --
select * from master..spt_values where type = @t

The second proc simply selects from the first proc

create proc getRecordsByStatus @t char(1)
as
select status, COUNT(*) CountRows from dbo.fn2_getRecords(@t)
group by status

And where you used to call

EXEC firstProc @param

to get a result, you now select from it

SELECT * FROM firstProc(@param)
RichardTheKiwi
  • 105,798
  • 26
  • 196
  • 262
12

You can capture the output from a stored procedure in a temp table and then use the table in your main query.

Capture the output of a stored procedure returning columns ID and Name to a table variable.

declare @T table (ID int, Name nvarchar(50))

insert into @T
exec StoredProcedure
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Mikael Eriksson
  • 136,425
  • 22
  • 210
  • 281
  • 1
    Excuse me... Did you say temp ***FILE***? While it's technically a feasible solution, I don't think I can afford writing and deleting huge temp files all the time. – isekaijin Feb 03 '11 at 17:46
  • 1
    Temp table, it was corrected in the answer but just wanted to clarify for future readers who might get confused by the above comment being out of date. – Cookie Mar 29 '17 at 08:46
  • 3
    I wish there was an `EXEC INTO #tmp` :-) – Simon_Weaver Nov 10 '18 at 03:33
6

Inserting the results of your stored proc into a table variable or temp table will do the trick.

If you're trying to reuse code in SQL Server from one query to the next, you have more flexibility with Table Functions. Views are all right if you don't need to pass parameters or use any kind of flow control logic. These may be used like tables in any other function, procedure, view or t-sql statement.

JeffO
  • 7,957
  • 3
  • 44
  • 53
3

If you made the procedure that returns the list into a table-valued function, then I believe you could use it in a sub-query.

Colin
  • 846
  • 7
  • 16
1

I would use a view, unless it needs to be parameterized, in which case I would use an inline table-valued function if possible, unless it needs to be a multi-statement operation, where you can still use a table-valued function, but they are usually less efficient.

Luke Girvin
  • 13,221
  • 9
  • 64
  • 84
Cade Roux
  • 88,164
  • 40
  • 182
  • 265
  • I need to take parameters to perform both queries. This is why I am using stored procedures. – isekaijin Feb 03 '11 at 21:12
  • @Eduardo Leon I would use an inline table-valued function if possible. These are really equivalent to parameterized views in terms of how the optimizer can treat them and combine them with any underlying views and whatever code is calling the ITVF. – Cade Roux Feb 03 '11 at 22:14
  • Can you call an ITVF in the `FROM` clause of a query? – isekaijin Feb 03 '11 at 23:25
  • @Eduado Leon Certainly - you can use an ITVF from a view (with static - or code-generated, if you generate views - parameters) or from another ITVF. In my experience, all views and ITVFs (if joined straighforwardly) get collapsed by the optimizer pretty efficiently if you look at the execution plans. – Cade Roux Feb 04 '11 at 04:32