The APPLY relational operator allows you to invoke a table-valued function once per each row of an outer table expression. You specify APPLY in the FROM clause of a query, similarly to the way you use the JOIN operator. APPLY can take two forms: CROSS APPLY and OUTER APPLY.
CROSS APPLY
CROSS APPLY invokes a
table-valued function for each row in an outer table expression,
returning a unified result set out of all the results returned by the
individual invocations of the table-valued function. The columns in the
outer table are used as arguments to the table-valued function. If the
table-valued function returns an empty set for a given outer row, that
outer row is not returned in the result.
For example, the table-valued function in Listing 1 accepts stor_id and an integer as arguments and returns a list of the top N
largest orders for that store. The number of rows returned is
determined by the value passed to the second parameter. If you call this
function with stor_id and a number of rows, it returns that many rows, ordered by the qty of the order, in descending order.
Listing 1. A Table-Valued Function That Returns the Top N Orders for stor_id
CREATE FUNCTION dbo.fn_GetTopOrders(@stor_id AS char(4), @n AS INT) RETURNS TABLE AS RETURN SELECT TOP(@n) * FROM dbo.sales WHERE stor_id = @stor_id ORDER BY qty DESC GO
|
Following is a sample invocation of the function in Listing 43.57:
select * from dbo.fn_GetTopOrders ('B251', 3)
go
stor_id ord_num ord_date qty payterms title_id
------- ------------------ ----------------------- ---- ------------ --------
B251 ONQQQQQQQQQQQQQQQ 2008-01-23 00:00:00.000 1740 Net 60 CH6808
B251 ONKKKKKKKKKKKKKKKK 2007-11-04 00:00:00.000 1704 Net 60 FI9420
B251 ONTTTTTTTTTTTTTTTT 2008-02-22 00:00:00.000 1560 Net 60 FI8000
If
you want to generate a result set that shows each store name and the
top three largest orders for each store, you can use the CROSS APPLY function to join to the dbo.fn_GetTopOrders function for each stor_id in the outer query, as shown in Listing 2.
Listing 2. Using CROSS APPLY
select st.stor_id, stor_name, s.ord_date, s.qty from stores st cross apply dbo.fn_GetTopOrders (st.stor_id, 3) as s where st.state = 'MI' and st.stor_name in ('Barnes & Noble', 'B Dalton BookSeller', 'Waldenbooks') order by stor_id, s.qty DESC go
stor_id stor_name ord_date qty ------- ------------------- ----------------------- ------ B251 B Dalton Bookseller 2008-01-23 00:00:00.000 1740 B251 B Dalton Bookseller 2007-11-04 00:00:00.000 1704 B251 B Dalton Bookseller 2008-02-22 00:00:00.000 1560 B510 Barnes & Noble 2008-08-13 00:00:00.000 1464 B510 Barnes & Noble 2007-10-08 00:00:00.000 1200 B510 Barnes & Noble 2006-01-08 00:00:00.000 924 P963 Waldenbooks 2008-07-07 00:00:00.000 1668 P963 Waldenbooks 2006-12-30 00:00:00.000 1068 P963 Waldenbooks 2006-03-29 00:00:00.000 1032 Q017 Waldenbooks 2007-11-02 00:00:00.000 1776 Q017 Waldenbooks 2006-06-15 00:00:00.000 1704 Q017 Waldenbooks 2007-02-24 00:00:00.000 1548
|
CROSS APPLY returns
only rows from the outer table that produce a result set from the
table-valued function. If a store has no orders, it does not appear in
the result set. To include all rows from the outer table, use OUTER APPLY.
OUTER APPLY
OUTER APPLY returns
from the outer table both rows that produce a result set and rows that
do not. Rows that do not produce a result set from the table-valued
function return NULL values in the columns produced by the table-valued function.
The following example is similar to the query in Listing 43.58 but replaces CROSS APPLY with the OUTER APPLY clause:
select st.stor_id, stor_name, s.ord_date, s.qty
from stores st
outer apply
dbo.fn_GetTopOrders (st.stor_id, 3) as s
where st.state = 'MI'
and st.stor_name in ('Barnes & Noble', 'B Dalton BookSeller', 'Waldenbooks')
order by stor_id, s.qty DESC
go
stor_id stor_name ord_date qty
------- ------------------- ----------------------- ------
B251 B Dalton Bookseller 2008-01-23 00:00:00.000 1740
B251 B Dalton Bookseller 2007-11-04 00:00:00.000 1704
B251 B Dalton Bookseller 2008-02-22 00:00:00.000 1560
B510 Barnes & Noble 2008-08-13 00:00:00.000 1464
B510 Barnes & Noble 2007-10-08 00:00:00.000 1200
B510 Barnes & Noble 2006-01-08 00:00:00.000 924
B511 Barnes & Noble NULL NULL
P963 Waldenbooks 2008-07-07 00:00:00.000 1668
P963 Waldenbooks 2006-12-30 00:00:00.000 1068
P963 Waldenbooks 2006-03-29 00:00:00.000 1032
Q017 Waldenbooks 2007-11-02 00:00:00.000 1776
Q017 Waldenbooks 2006-06-15 00:00:00.000 1704
Q017 Waldenbooks 2007-02-24 00:00:00.000 1548