Home > Database > MS SQL Server > CROSS APPLY and OUTER APPLY in SQL Server

CROSS APPLY and OUTER APPLY in SQL Server

In this article, we are learning the use of the CROSS APPLY and OUTER APPLY

SQL Server APPLY operator has two variants: CROSS APPLY and OUTER APPLY

  • The CROSS APPLY operator returns only those rows from the left table expression (in its final output) if it matches with the right table expression. In other words, the right table expression returns rows for the left table expression match only.
  • The OUTER APPLY operator returns all the rows from the left table expression irrespective of its match with the right table expression. For those rows for which there are no corresponding matches in the right table expression, it contains NULL values in columns of the right table expression. So you might conclude, the CROSS APPLY is equivalent to an INNER JOIN (or to be more precise its like a CROSS JOIN with a correlated sub-query) with an implicit join condition of 1=1 whereas the OUTER APPLY is equivalent to a LEFT OUTER JOIN.
  • You might be wondering if the same can be achieved with a regular JOIN clause, so why and when do you use the APPLY operator? Although the same can be achieved with a normal JOIN, the need of APPLY arises if you have a table-valued expression on the right part and in some cases the use of the APPLY operator boosts performance of your query. Let me explain with some examples.

Below is the Sample Example for the CROSS APPLY and OUTER APPLY

Script #1: Create and Insert some Data in Tables

USE [tempdb]

go

IF EXISTS (SELECT *
           FROM   sys.objects
           WHERE  object_id = Object_id(N'[Employee]’)
                  AND type IN ( N’U’ ))
  BEGIN
      DROP TABLE [employee]
  END

go

IF EXISTS (SELECT *
           FROM   sys.objects
           WHERE  object_id = Object_id(N'[Department]’)
                  AND type IN ( N’U’ ))
  BEGIN
      DROP TABLE [department]
  END

CREATE TABLE [department]
  (
     [departmentid] [INT] NOT NULL PRIMARY KEY,
     [name]         VARCHAR(250) NOT NULL,
  )
ON [PRIMARY]
INSERT [department]([departmentid],[name]) VALUES (1, N’Engineering’)
INSERT [department]([departmentid],[name]) VALUES (2, N’Administration’)
INSERT [department]([departmentid],[name]) VALUES (3, N’Sales’)
INSERT [department]([departmentid],[name]) VALUES (4, N’Marketing’)
INSERT [department]([departmentid],[name]) VALUES (5, N’Finance’)
go
CREATE TABLE [employee]
  (
     [employeeid]   [INT] NOT NULL PRIMARY KEY,
     [firstname]    VARCHAR(250) NOT NULL,
     [lastname]     VARCHAR(250) NOT NULL,
     [departmentid] [INT] NOT NULL REFERENCES [department](departmentid),
  )
ON [PRIMARY]
go

INSERT [employee]([employeeid],[firstname],[lastname],[departmentid]) VALUES (1,N’Orlando’,N’Gee’,1)
INSERT [employee]([employeeid],[firstname],[lastname],[departmentid]) VALUES (2,N’Keith’,N’Harris’,2)
INSERT [employee]([employeeid],[firstname],[lastname],[departmentid]) VALUES (3,N’Donna’,N’Carreras’,3)
INSERT [employee]([employeeid],[firstname],[lastname],[departmentid]) VALUES (4,N’Janet’,N’Gates’,3)

SELECT * FROM   department
SELECT * FROM   employee

SQL Server CROSS APPLY vs INNER JOIN example

Script #2: CROSS APPLY vs INNER JOIN


SELECT *
FROM   department D
       CROSS apply (SELECT *
                    FROM   employee E
                    WHERE  E.departmentid = D.departmentid) A

go

SELECT *
FROM   department D
       INNER JOIN employee E
               ON D.departmentid = E.departmentid

go

SQL Server OUTER APPLY vs LEFT OUTER JOIN example

Script #3: OUTER APPLY vs LEFT OUTER JOIN

SELECT *
FROM   department D
       OUTER apply (SELECT *
                    FROM   employee E
                    WHERE  E.departmentid = D.departmentid) A

go

SELECT *
FROM   department D
       LEFT OUTER JOIN. employee E
                    ON D.departmentid = E.departmentid

go

Joining table valued functions and tables using APPLY operators

Script #4: Joining table valued functions with APPLY Operators

IF EXISTS (SELECT *
           FROM   sys.objects
           WHERE  object_id = Object_id(N'[fn_GetAllEmployeeOfADepartment]’)
                  AND type IN ( N’IF’ ))
  BEGIN
      DROP FUNCTION dbo.fn_getallemployeeofadepartment
  END

go

CREATE FUNCTION dbo.Fn_getallemployeeofadepartment(@DeptID AS INT)
returns TABLE
AS
    RETURN
      (SELECT *
       FROM   employee E
       WHERE  E.departmentid = @DeptID)

go

SELECT *
FROM   department D
       CROSS apply dbo.Fn_getallemployeeofadepartment(D.departmentid)

go

SELECT *
FROM   department D
       OUTER apply dbo.Fn_getallemployeeofadepartment(D.departmentid)

go 

You might be wondering if we can use a simple join in place of the above queries, the answer is NO. If you replace the CROSS/OUTER APPLY in the Script #4 with an INNER JOIN/LEFT OUTER JOIN, specifying the ON clause with 1=1 and run the query, you will get the error “The multi-part identifier “D.DepartmentID” could not be bound.”. This is because with JOINs the execution context of the outer query is different from the execution context of the function (or a derived table), and you cannot bind a value/variable from the outer query to the function as a parameter. Hence the APPLY operator is required for such queries. So in summary the APPLY operator is required when you have to use a table-valued function in the query, but it can also be used with inline SELECT statements.

This Article is TAGGED in , , . BOOKMARK THE permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">