DATETIME SELECT SELECT INTO DATE PAD STRING DYNAMIC SQL CURSOR MONEY FORMAT PERCENT STORED PROCEDURE SQL SERVER AGENT JOB OPTIMIZATION WHILE LOOP OVER PARTITION BY UPDATE
SITE SEARCH SQLUSA.com HEADLINES NEWS
SQL E/BOOKS  SQL 2012 PROGRAMMING  DOWNLOADS
SCRIPTS SQL 2005 SQL 2008 ARTICLES
SQL JOBS TWITTER FORMAT VIDEOS

 

All the Fuss about CROSS APPLY

By Kalman Toth, M.Phil. Physics, M.Phil. Computing Science, MCDBA, MCITP

March 14 , 2011

Since 2004 there is buzz in SQL circles about CROSS APPLY, a new feature of SQL Server 2005. Actually, CROSS APPLY is quite simple: a restricted "INNER JOIN" between a table (outer query) and a table-valued function (common usage), or derived table from correlated subquery. The table-valued function is evaluated only for the paramater values supplied by the outer query. Here is a quick example for CROSS APPLY usage applying a DMV and a DMF:

-- SQL Cross Apply quick syntax - SELECT * last ran stats

SELECT deqs.last_execution_time AS LastRun, dest.TEXT AS QueryText, *

FROM sys.dm_exec_query_stats AS deqs

CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest

WHERE LEFT(dest.TEXT,8)='SELECT *'

ORDER BY LastRun DESC

The results generated by CROSS APPLY queries can be achieved without using CROSS APPLY by applying a temporary table, common table expression or table variables. However, that is a bit tedious. The application of CROSS APPLY in conjunction with a table-valued function yields a neat and very powerful solution in a single well structured query.

When we take the AdventureWorks2008 sample database product table we see that the ProductID-s are not continuous by color. The following exercise finds the missing ID-s for each color to make it a perfect sequence with the application of CROSS APPLY and nested CTE-s. The fnRange table-valued UDF generates a sequence between two integers. We use LEFT JOIN to find the "gap" numbers.

CREATE FUNCTION fnRange ( @Start int, @End int)

RETURNS TABLE AS

RETURN (SELECT * FROM (SELECT SEQ=ROW_NUMBER() OVER (ORDER BY (SELECT 1))

    FROM   MASTER.dbo.spt_values a

           -- CROSS JOIN MASTER.dbo.spt_values b -- uncomment for more range

           ) x

           WHERE SEQ BETWEEN @Start AND @End)

GO

 

;WITH CTE (Color, MinID, MaxID) AS

 (SELECT Color, MIN(ProductID), MAX(ProductID)

  FROM Production.Product

  WHERE Color is not null  GROUP BY Color),

  cteSEQ AS (SELECT Color, SEQ FROM CTE

             CROSS APPLY  dbo.fnRange (MinID, MaxID) as R)

 SELECT  *, P.Color, I.SEQ

 FROM cteSEQ I LEFT JOIN Production.Product P

   ON I.SEQ = P.ProductID AND I.Color = P.Color

      AND P.Color is not null

   WHERE P.ProductID is  null

 ORDER BY I.Color, I.SEQ

 /* Missing from continuous ID sequence

 Color      SEQ

Black       317

Black       318

Black       319

Black       320

Black       321

.... */

In another article I mentioned that CROSSTAB reports are excellent career boosters for database developers and DBA-s. So are CROSS APPLY reports.

In the first three T-SQL examples we use derived table (as opposed to table-valued function) for CROSS APPLY.

------------
-- T-SQL column aliasing with CROSS APPLY
------------
SELECT TranID, ProdID, Qty, Cost, TotalCost=Qty * Cost
FROM AdventureWorks2008.Production.TransactionHistory
 CROSS APPLY
 (SELECT TranID = TransactionID
        ,ProdID = ProductID
        ,Qty = Quantity
        ,Cost = ActualCost ) x
 WHERE Qty > 10 and Cost > 0.0
 ORDER BY TranID, ProdID
 /* TranID  ProdID      Qty   Cost        TotalCost
100154      864         14    41.275      577.85
100157      869         24    45.4935     1091.844
100198      869         16    45.4935     727.896
....
*/

------------

------------

-- CROSS APPLY using GROUP BY derived table from correlated subquery

------------

USE AdventureWorks;

DECLARE  @Year  INT,

         @Month INT

SET @Year = 2003;

SET @Month = 2

 

-- SQL cross apply - SQL group by - SQL correlated subquery

SELECT [Customer] = s.Name,

       -- Special money data type currency formatting option

       [Total$ Sales] = '$' +

        Convert(VARCHAR,Convert(MONEY,SalesAmount.OrderTotal),1)

FROM     Sales.Customer AS c

         -- The customer name is in this table

         INNER JOIN Sales.Store AS s

           ON s.CustomerID = c.CustomerID

         -- The inner query is a correlated GROUP BY subquery

         CROSS APPLY (SELECT   soh.CustomerId,

                               Sum(sod.LineTotal) AS OrderTotal

                      FROM     Sales.SalesOrderHeader AS soh

                               INNER JOIN Sales.SalesOrderDetail AS sod

                                 ON sod.SalesOrderId = soh.SalesOrderId

                      -- This is the correlation to the outer query

                     WHERE soh.CustomerId = c.CustomerId

                               -- Filter data

                               AND Year(OrderDate) = @Year

                               AND Month(OrderDate) = @Month

                      GROUP BY soh.CustomerId) AS SalesAmount

ORDER BY [Customer]

 

GO

/* Partial results

 

(132 row(s) affected)

 

Customer                      Total$ Sales

Ace Bicycle Supply            $647.99

Affordable Sports Equipment   $50,953.32

Alpine Ski House              $939.59

Basic Sports Equipment        $159.56

Bicycle Lines Distributors    $22,243.33

*/

 

/**** OUTER APPLY results: (701 row(s) affected) ********/

------------

-- CROSS APPLY using derived table from correlated subquery

------------

-- Create and populate tables for testing

USE tempdb;

GO

SET NOCOUNT ON;

CREATE TABLE Account (

  AccountID   INT    IDENTITY    PRIMARY KEY,

  AccountName VARCHAR(50),

  CreateDate  SMALLDATETIME    DEFAULT (CURRENT_TIMESTAMP),

  IsActive    BIT    DEFAULT (1))

 

GO

 

CREATE TABLE Deposit (

  DepositId   INT    IDENTITY    PRIMARY KEY,

  AccountID       INT,

  Amount          MONEY,

  DepositDate SMALLDATETIME    DEFAULT (getdate()))

 

GO

INSERT Account(AccountName) VALUES ('Charles Mills')

INSERT Account(AccountName) VALUES ('Miranda Vegas')

INSERT Account(AccountName) VALUES ('Corner Hardware')

INSERT Account(AccountName) VALUES ('Laptop Land')

INSERT Account(AccountName) VALUES ('Cellphone City')

SELECT * FROM Account

/*

AccountID   AccountName       CreateDate              IsActive

1           Charles Mills     2015-01-25 08:38:00     1

2           Miranda Vegas     2015-01-25 08:38:00     1

3           Corner Hardware   2015-01-25 08:38:00     1

4           Laptop Land       2015-01-25 08:38:00     1

5           Cellphone City    2015-01-25 08:38:00     1

*/

 

INSERT Deposit (AccountID, Amount) VALUES(1, 1400.0)

INSERT Deposit (AccountID, Amount) VALUES(1, 1200.0)

INSERT Deposit (AccountID, Amount) VALUES(1, 1300.0)

INSERT Deposit (AccountID, Amount) VALUES(1, 1100.0)

INSERT Deposit (AccountID, Amount) VALUES(2, 400.0)

INSERT Deposit (AccountID, Amount) VALUES(2, 200.0)

INSERT Deposit (AccountID, Amount) VALUES(2, 300.0)

INSERT Deposit (AccountID, Amount) VALUES(2, 900.0)

INSERT Deposit (AccountID, Amount) VALUES(3, 33400.0)

INSERT Deposit (AccountID, Amount) VALUES(3, 11200.0)

INSERT Deposit (AccountID, Amount) VALUES(3, 22300.0)

INSERT Deposit (AccountID, Amount) VALUES(3, 12100.0)

GO

 

-- CROSS APPLY returns only matching data - SQL cross apply

-- Cross apply T-SQL - Cross apply mssql - derived table - SQL correlated subquery

SELECT   a.AccountName,

         TopDeposit=tt.Amount

FROM     ACCOUNT a

CROSS APPLY (SELECT   TOP ( 1 ) Amount

             FROM     Deposit t

             WHERE    t.AccountID = a.AccountID

             ORDER BY Amount DESC) tt

ORDER BY AccountName

/*

AccountName       TopDeposit

Corner Hardware   33400.00

Miranda Vegas     900.00

Charles Mills     1400.00

*/

 

 

-- Cleanup

DROP TABLE tempdb.dbo.Account

DROP TABLE tempdb.dbo.Deposit

------------

 

In the following example, the table-valued inline function returns the top 5 (highest TotalDue) orders for a store or individual customer, provided there are 5 orders. The SELECT query itself is restricted to stores. CROSS APPLY joins the store information with the top 5 orders information produced by the table-valued function.

USE AdventureWorks;

GO

-- SQL inline function

-- User-defined inline function

CREATE FUNCTION Sales.fnTopNOrders (

      @CustomerID AS INT,

      @n AS INT )

RETURNS TABLE

AS

RETURN

SELECT

      TOP(@n) SalesOrderID,

      ShipDate = convert(char(10), ShipDate,112),

-- SQL currency formatting

      TotalDue=convert(varchar,TotalDue,1)

FROM AdventureWorks.Sales.SalesOrderHeader

WHERE CustomerID = @CustomerID

ORDER BY TotalDue DESC

GO

 

-- SQL cross apply - SQL Server cross apply

SELECT

      StoreName=s.Name,

      [Top].ShipDate,

      [Top].SalesOrderID,

      TotalDue='$'+[Top].TotalDue

FROM AdventureWorks.Sales.Store AS s

JOIN AdventureWorks.Sales.Customer AS c

ON s.CustomerID = c.CustomerID

 

CROSS APPLY

 

AdventureWorks.Sales.fnTopNOrders(c.CustomerID, 5) AS [Top]

WHERE CustomerType='S'

ORDER BY StoreName, convert(money,TotalDue) DESC

GO

 
Partial result set:

StoreName ShipDate SalesOrderID TotalDue
A Bike Store 20020208 45283 $37,643.14
A Bike Store 20020508 46042 $34,722.99
A Bike Store 20011108 44501 $26,128.87
A Bike Store 20010808 43860 $14,603.74
A Great Bicycle Company 20010908 44125 $3,450.98
A Great Bicycle Company 20020308 45569 $2,828.58
A Great Bicycle Company 20011208 44793 $2,828.58
A Great Bicycle Company 20030308 49537 $622.95
A Great Bicycle Company 20031208 59009 $50.77
A Typical Bike Shop 20020608 46343 $39,156.33
A Typical Bike Shop 20011208 44755 $37,725.60

The CROSS APPLY operator is frequently used in joining DMVs with DMFs (Dynamic Management Views with Dynamic Management Functions). In the following examples the sys.dm_exec_sql_text DMF returns the source text for the cached plans and queries like CREATE PROCEDURE, SELECT..., CREATE VIEW, etc..

-- SQL cross apply - Cross apply mssql

-- SQL dynamic management view - dmv - SQL dynamic management function - dmf

SELECT   LastExecutionTime = max(last_execution_time),

         Query = Text

FROM     sys.dm_exec_query_stats AS eqs

CROSS APPLY sys.dm_exec_sql_text(eqs.sql_handle) AS SQL

WHERE    Text LIKE ('%AdventureWorks%')

         AND Text NOT LIKE ('%fullText%')

GROUP BY Text

ORDER BY Query

GO

/* Partial results

 

LastExecutionTime             Query

2009-01-24 09:42:23.217       SELECT EmployeeID, StaffName = LastName+',....  

2009-01-24 10:31:49.170       SELECT e.EmployeeID, e.Title, StaffName = ....

*/

-- SQL Server cross apply

SELECT 

      PlanSource=sql.text,

      plans.*

FROM  sys.dm_exec_cached_plans plans

CROSS APPLY  sys.dm_exec_sql_text (plans.plan_handle) AS sql

 

The following CROSS APPLY query returns sql source and information about all executing requests within SQL Server:

-- SQL cross apply

SELECT

      RequestSource = sql.text,

      er.*

FROM

sys.dm_exec_requests er

CROSS APPLY

sys.dm_exec_sql_text(sql_handle) AS sql
GO

 

The following CROSS APPLY example script creates the Employee table in tempdb with select into from HumanResources tables in AdventureWorks. To be used with CROSS APPLY, the T-SQL script creates a table-valued orginazational chart subtree function by applying recursive CTE. The new tree-processing UDF is used in CROSS APPLY queries:

 

USE tempdb;

GO

-- SQL select into create table - SQL inner join

SELECT      e.EmployeeID, e.Title, StaffName = LastName+', '+FirstName,

            ManagerID, Department=d.Name 

INTO Employee

FROM AdventureWorks.HumanResources.Employee e

INNER JOIN AdventureWorks.HumanResources.EmployeeDepartmentHistory edh

      ON e.EmployeeID = edh.EmployeeID

INNER JOIN AdventureWorks.HumanResources.Department d

      ON edh.DepartmentID = d.DepartmentID

INNER JOIN AdventureWorks.Person.Contact c

      ON e.ContactID = c.ContactID

WHERE edh.EndDate is NULL

GO

-- SELECT * FROM Employee

 

-- SQL table-valued function - user-defined function UDF - Tree processing function

CREATE FUNCTION fnOrgChartSubTree(@EmployeeID AS INT)

    RETURNS @TREE TABLE (

             EmployeeID             INT

            ,EmployeeName           VARCHAR(35)

            ,Department             VARCHAR(30)

            ,ManagerID              INT

            ,ManagerName            VARCHAR(35)

            ,OrgChartLevel          INT )

AS

BEGIN

-- SQL common table expression - CTE - SQL recursive CTE

  WITH cteOrgChartSubTree(EmployeeID, EmployeeName, Department,

                  ManagerID, ManagerName, OrgChartLevel)

  AS

  (

    -- Anchor (root) node

    SELECT e1.EmployeeID, e1.StaffName, e1.Department,

           e1.ManagerID, e2.StaffName, 0

    FROM Employee e1

    LEFT JOIN Employee e2

    ON (e1.ManagerID = e2.EmployeeID)

    WHERE e1.EmployeeID = @EmployeeID

 

    UNION ALL

   

    -- Recursive nodes to leaf level

    SELECT  e1.EmployeeID, e1.StaffName, e1.Department,

                  e1.ManagerID, e2.StaffName, cte.OrgChartLevel+1

    FROM Employee e1

    INNER JOIN Employee e2

            ON e1.ManagerID = e2.EmployeeID

    JOIN cteOrgChartSubTree AS cte

        ON e1.ManagerID = cte.EmployeeID

  )

-- Return results

  INSERT INTO @TREE

  SELECT * FROM cteOrgChartSubTree;

  RETURN

END

GO

 

-- Find CEO

SELECT CEO=StaffName, CEOid =EmployeeID

FROM Employee

WHERE ManagerID is NULL

GO

/* Results

CEO                     CEOid

Sánchez, Ken            109

*/

 

-- Test UDF - user-defined function

-- Generate orgchart starting with CEO

SELECT EmpID = EmployeeID, EmpName=EmployeeName, Department,

MgrID=ManagerID, MgrName=ManagerName, OCLvl=OrgChartLevel

FROM dbo.fnOrgChartSubTree(109)

GO

/* 290 rows - Partial results

EmpID EmpName           Department  MgrID MgrName           OCLvl

109   Sánchez, Ken      Executive   NULL  NULL              0

6     Bradley, David    Marketing   109   Sánchez, Ken      1

12    Duffy, Terri      Engineering 109   Sánchez, Ken      1

42    Trenary, Jean     Informa…    109   Sánchez, Ken      1

140   Norman, Laura     Executive   109   Sánchez, Ken      1

148   Hamilton, James   Production  109   Sánchez, Ken      1

273   Welcker, Brian    Sales       109   Sánchez, Ken      1

268   Jiang, Stephen    Sales       273   Welcker, Brian    2

284   Alberts, Amy      Sales       273   Welcker, Brian    2

*/

 

-- Test UDF for supervisor Miller, Dylan

SELECT EmpID = EmployeeID, EmpName=EmployeeName, Department,

MgrID=ManagerID, MgrName=ManagerName, OCLvl=OrgChartLevel

FROM dbo.fnOrgChartSubTree(158)

GO

/* Results

   R & D = Research and Development

  

EmpID EmpName           Department  MgrID MgrName           OCLvl

158   Miller, Dylan     R & D       3     Tamburello…       0

79    Margheim, Diane   R & D       158   Miller, Dylan     1

114   Matthew, Gigi     R & D       158   Miller, Dylan     1

217   Raheem, Michael   R & D       158   Miller, Dylan     1

*/

 

-- Test UDF for staff Margheim, Diane (leaf level on orgchart tree)

SELECT EmpID = EmployeeID, EmpName=EmployeeName, Department,

MgrID=ManagerID, MgrName=ManagerName, OCLvl=OrgChartLevel

FROM dbo.fnOrgChartSubTree(79)

GO

/* Results

 

EmpID EmpName           Department        MgrID       MgrName           OCLvl

79    Margheim, Diane   Research and...   158         Miller, Dylan     0

*/

 

-- Get top-level executives - Level 1 when root is  CEO

-- SQL select into create temporary table - SQL cross apply

SELECT ExecName=oc.EmployeeName, oc.EmployeeID, oc.Department

INTO #EXECS

FROM Employee e

CROSS APPLY dbo.fnOrgChartSubTree(e.EmployeeID) AS oc

WHERE e.EmployeeID = 109

and oc.OrgChartLevel=1;

SELECT * FROM #EXECS

GO

/* Results

 

ExecName          EmployeeID  Department

Bradley, David    6           Marketing

Duffy, Terri      12          Engineering

Trenary, Jean     42          Information Services

Norman, Laura     140         Executive

Hamilton, James   148         Production

Welcker, Brian    273         Sales

*/

 

-- Get orgchart by executives

-- Note: AdventureWorks database does not have Department Manager info

-- SQL cross apply - SQL IN operator

SELECT      Executive=e.StaffName, e.Title, oc.Department, 

            Staff=oc.EmployeeName, Supervisor = oc.ManagerName

FROM Employee e

CROSS APPLY dbo.fnOrgChartSubTree(e.EmployeeID) AS oc

WHERE e.EmployeeID IN (Select EmployeeID FROM #EXECS)

ORDER by Executive, Department, Supervisor, Staff

GO

/* 289 rows CEO Ken Sanchez not included - Partial results

   VPS = Vice President of Sales

   WB = Welcker, Brian

   Dept = Department

  

Executive   Title Dept  Staff                   Supervisor

WB          VPS   Sales Tsoflias, Lynn          Abbas, Syed

WB          VPS   Sales Pak, Jae                Alberts, Amy

WB          VPS   Sales Valdez, Rachel          Alberts, Amy

WB          VPS   Sales Varkey C.., Ranjit      Alberts, Amy

WB          VPS   Sales Ansman-W.., Pamela      Jiang, Stephen

WB          VPS   Sales Blythe, Michael         Jiang, Stephen

WB          VPS   Sales Campbell, David         Jiang, Stephen

WB          VPS   Sales Carson, Jillian         Jiang, Stephen

WB          VPS   Sales Ito, Shu                Jiang, Stephen

WB          VPS   Sales Mensa-A.., Tete         Jiang, Stephen

WB          VPS   Sales Mitchell, Linda         Jiang, Stephen

WB          VPS   Sales Reiter, Tsvi            Jiang, Stephen

WB          VPS   Sales Saraiva, José           Jiang, Stephen

WB          VPS   Sales Vargas, Garrett         Jiang, Stephen

WB          VPS   Sales Welcker, Brian          Sánchez, Ken

WB          VPS   Sales Abbas, Syed             Welcker, Brian

WB          VPS   Sales Alberts, Amy            Welcker, Brian

WB          VPS   Sales Jiang, Stephen          Welcker, Brian

*/

 

-- Cleanup

DROP TABLE tempdb.dbo.Employee

DROP TABLE #EXECS

GO

 

 

In the following sql CROSS APPLY example, first we create a function (UDF) to get the total sales for a bike store. Second, we use CROSS APPLY to get the sales figures for the early dealers (CustomerID < 100) of AdventureWorks Cycles. Naturally, we can achieve the same results in a single complex query which may even be faster. The CROSS APPLY advantage appears when the user-defined function is used in several queries: developer productivity gain.  

 

  

-- SQL create function

USE AdventureWorks;

GO

CREATE FUNCTION dbo.fnGetTotalSalesByCustomer(@CustID  int)

  RETURNS TABLE

AS

RETURN

  SELECT    Store = s.Name,

                  TotalSales = '$'+convert(varchar,TotalSales,1)

  FROM

  (

      SELECT CustomerID = @CustID, TotalSales=sum(SubTotal)

      FROM Sales.SalesOrderHeader

      WHERE CustomerID =@CustID

  ) soh

  INNER JOIN Sales.Store s

  ON soh.CustomerID = s.CustomerID

 GO

 

-- SQL cross apply use - SQL Server cross apply

SELECT  Store, TotalSales

FROM Sales.Customer AS c

CROSS APPLY dbo.fnGetTotalSalesByCustomer (c.CustomerID) tsc

WHERE c.CustomerID < 100

ORDER BY Store

GO

 

/* Partial results

 

Store                                     TotalSales

A Bike Store                              $102,351.80

Advanced Bike Components                  $433,942.38

Aerobic Exercise Company                  $3,301.21

Associated Bikes                          $9,384.45

Bicycle Exporters                         $37,684.82

Bicycle Warehouse Inc.                    $7,959.01

Bike World                                $112,601.32

*/

In the following example we calculate financial statistics using Aggregate Functions for each dealer which sells AdventureWorks mountain bikes and associated products.

Here is the listing:

USE tempdb

 

GO

 

-- drop FUNCTION dbo.fnOrderFingerprint

CREATE FUNCTION dbo.fnOrderFingerprint

               (@CustomerID AS INT)

RETURNS TABLE

AS

  RETURN

    SELECT Label = 'Maximum $',

           TotalDue = max(TotalDue)

    FROM   AdventureWorks.Sales.SalesOrderHeader

    WHERE  CustomerID = @CustomerID

    UNION

    SELECT Label = 'Average $',

           TotalDue = avg(TotalDue)

    FROM   AdventureWorks.Sales.SalesOrderHeader

    WHERE  CustomerID = @CustomerID

    UNION

    SELECT Label = 'Minimum $',

           TotalDue = min(TotalDue)

    FROM   AdventureWorks.Sales.SalesOrderHeader

    WHERE  CustomerID = @CustomerID

    UNION

    SELECT Label = 'Order Count',

           TotalDue = count(TotalDue)

    FROM   AdventureWorks.Sales.SalesOrderHeader

    WHERE  CustomerID = @CustomerID

    UNION

    SELECT Label = 'Standard Deviation $',

           TotalDue = stdev(TotalDue)

    FROM   AdventureWorks.Sales.SalesOrderHeader

    WHERE  CustomerID = @CustomerID

 

GO

 

SELECT   Customer = S.Name,

         F.Label,

         [Total Due] = left(convert(VARCHAR,convert(MONEY,F.TotalDue),1),

                            len(convert(VARCHAR,convert(MONEY,F.TotalDue),1)) - 3)

FROM     AdventureWorks.Sales.Store AS S

         JOIN AdventureWorks.Sales.Customer AS C

           ON S.CustomerID = C.CustomerID

         CROSS APPLY tempdb.dbo.fnOrderFingerprint(C.CustomerID) AS F

ORDER BY Customer ASC,

         Label DESC

 

GO

This is the partial report:

Customer Label TotalDue
Excellent Riding Supplies Standard Deviation $ 34,246
Excellent Riding Supplies Order Count 12
Excellent Riding Supplies Minimum $ 34,102
Excellent Riding Supplies Maximum $ 150,167
Excellent Riding Supplies Average $ 94,562
Exceptional Cycle Services Standard Deviation $ 3,978
Exceptional Cycle Services Order Count 4
Exceptional Cycle Services Minimum $ 4,012
Exceptional Cycle Services Maximum $ 13,016
Exceptional Cycle Services Average $ 7,913
Exchange Parts Inc. Standard Deviation $ 3,965
Exchange Parts Inc. Order Count 4
Exchange Parts Inc. Minimum $ 34,610
Exchange Parts Inc. Maximum $ 43,277
Exchange Parts Inc. Average $ 38,982
Exclusive Bicycle Mart Standard Deviation $ 576
Exclusive Bicycle Mart Order Count 6
Exclusive Bicycle Mart Minimum $ 429
Exclusive Bicycle Mart Maximum $ 1,943
Exclusive Bicycle Mart Average $ 1,035

 

Related articles:

Returning Complex Data from User-Defined Functions with CROSS APPLY

Using APPLY

SQL Server CROSS APPLY and OUTER APPLY

 

Exam Prep 70-461
Exam 70-461
DATETIME SELECT SELECT INTO DATE PAD STRING DYNAMIC SQL CURSOR MONEY FORMAT PERCENT STORED PROCEDURE SQL SERVER AGENT JOB OPTIMIZATION WHILE LOOP OVER PARTITION BY UPDATE