Processing rows in one set using another set is a common coding pattern used mostly with combining or comparing rows from sets. SQL Server offers three set operators: UNION, INTERSECT and EXCEPT, for handling scenario which compares rows from one set to another and completes the return set. In some specific cases, an alternative operator which is APPLY can be used for handling similar scenario. Here is post on APPLY operator;
The APPLY operator not exactly a set operator. It is a table operator which evaluates rows in one set based on an expression set with another set, NOT combining two sets in similar manner used by other set operators but like a JOIN. It is used with FROM clause and just like JOINs, two sets are marked as “left” set and “right” set. The “right” set is always either a table-valued function or a derived table which gets processed for each row returning from the “left” set. The syntax for APPLY is as follows;
SELECT <column list>
FROM <left-table> AS <alias>
APPLY <derived table | table-valued function> AS <alias>
There are two types of APPLY: CROSS APPLY and OUTER APPLY.
CROSS APPLY
CROSS APPLY processes the “right” set for each row found in the “left” set in a similar CROSS-JOIN manner. However, if an empty result is generated by the “right” set for the correlated row given by “left”, the row will NOT be included in the resultset, in a similar INNER-JOIN fashion. Here is an example for CROSS APPLY.
- USE AdventureWorks2012
- GO
- -- This returns all products
- -- There are 504 products
- SELECT ProductID, Name
- FROM Production.Product
- ORDER BY ProductID
- GO
- -- Create a table-valued function that returns top orders related to given product
- CREATE FUNCTION dbo.GetTopOrdersForTheProduct (@ProductId int)
- RETURNS TABLE
- AS
- RETURN
- SELECT TOP (2) h.SalesOrderNumber, h.OrderDate, (d.OrderQty * d.UnitPrice) OrderAmount
- FROM Sales.SalesOrderHeader h
- INNER JOIN Sales.SalesOrderDetail d
- ON h.SalesOrderID = d.SalesOrderID
- WHERE ProductID = @ProductId
- ORDER BY (d.OrderQty * d.UnitPrice) DESC
- GO
- -- check the function
- -- this does not return any records as there are no order for the product id 1
- SELECT * FROM dbo.GetTopOrdersForTheProduct (1)
- -- this returns records as there are orders for the product 707
- SELECT * FROM dbo.GetTopOrdersForTheProduct (707)
- -- Joining SELECT with TVF using CROSS APPLY
- -- This does not return products like 1, 2
- SELECT ProductID, Name, o.SalesOrderNumber, o.OrderDate, o.OrderAmount
- FROM Production.Product
- CROSS APPLY
- dbo.GetTopOrdersForTheProduct (ProductID) o
- ORDER BY ProductID
OUTER APPLY
The behavior of OUTER APPLY is same as CROSS APPLY except one which is the only difference between CROSS APPLY and OUTER APPLY. In the presence of an empty result from “right” set, CROSS APPLY excludes the row found in “left” from the returned result but OUTER APPLY includes it. This behavior is conceptually similar to LEFT OUTER JOIN. Here is the code describing it;
- -- Joining SELECT with TVF using CROSS APPLY
- -- This returns all from Product table
- SELECT ProductID, Name, o.SalesOrderNumber, o.OrderDate, o.OrderAmount
- FROM Production.Product
- OUTER APPLY
- dbo.GetTopOrdersForTheProduct (ProductID) o
- ORDER BY ProductID
No comments:
Post a Comment