2016-11-17 92 views
4

我在SQL Server中阅读了有关CROSS APPLYOUTER APPLY的文章。以下表格用于说明两者。OUTER适用于子查询

Employee表:

EmployeeID FirstName LastName DepartmentID 

1   Orlando  Gee   1 
2   Keith  Harris  2 
3   Donna  Carreras 3 
4   Janet  Gates  3 

系表:

DepartmentID Name 
1    Engineering 
2    Administration 
3    Sales 
4    Marketing 
5    Finance 

我了解,OUTER APPLY类似于LEFT OUTER JOIN.但是,当我申请如下表之间OUTER APPLY

select * from Department e 
outer apply 
Employee d 
where d.DepartmentID = e.DepartmentID 

我得到低于结果(S AME如INNER JOIN结果)

DepartmentID Name   EmployeeID FirstName LastName DepartmentID 
1    Engineering  1   Orlando  Gee   1 
2    Administration 2   Keith  Harris  2 
3    Sales   3   Donna  Carreras  3 
3    Sales   4   Janet  Gates  3 

当我表之间施加OUTER APPLY如下面(与right table为子查询)。

select * from Department e 
outer apply 
(
select * from 
Employee d 
where d.DepartmentID = e.DepartmentID 
)a 

我得到以下结果(同LEFT OUTER JOIN结果)

DepartmentID Name   EmployeeID FirstName LastName DepartmentID 
1    Engineering  1   Orlando  Gee   1 
2    Administration 2   Keith  Harris  2 
3    Sales   3   Donna  Carreras  3 
3    Sales   4   Janet  Gates  3 
4    Marketing  NULL  NULL  NULL   NULL 
5    Finance   NULL  NULL  NULL   NULL 

有人可以解释为什么这两个查询了不同outputs

回答

7

我认为关键要理解,这是看到了这个查询的输出:

select * from Department e 
outer apply 
Employee d 
--where d.DepartmentID = e.DepartmentID 

它只是给你两个表的笛卡尔乘积:

DepartmentID Name   EmployeeID FirstName LastName DepartmentID 
-------------------------------------------------------------------------------------- 
1    Engineering  1   Orlando  Gee   1 
2    Administration 1   Orlando  Gee   1 
3    Sales   1   Orlando  Gee   1 
4    Marketing  1   Orlando  Gee   1 
5    Finance   1   Orlando  Gee   1 
1    Engineering  2   Keith  Harris  2 
2    Administration 2   Keith  Harris  2 
3    Sales   2   Keith  Harris  2 
4    Marketing  2   Keith  Harris  2 
5    Finance   2   Keith  Harris  2 
1    Engineering  3   Donna  Carreras 3 
2    Administration 3   Donna  Carreras 3 
3    Sales   3   Donna  Carreras 3 
4    Marketing  3   Donna  Carreras 3 
5    Finance   3   Donna  Carreras 3 
1    Engineering  4   Janet  Gates  3 
2    Administration 4   Janet  Gates  3 
3    Sales   4   Janet  Gates  3 
4    Marketing  4   Janet  Gates  3 
5    Finance   4   Janet  Gates  3 

现在,当您添加回在where子句where d.DepartmentID = e.DepartmentID中,您将消除大部分这些行:

DepartmentID Name   EmployeeID FirstName LastName DepartmentID 
-------------------------------------------------------------------------------------- 
1    Engineering  1   Orlando  Gee   1 
2    Administration 2   Keith  Harris  2 
3    Sales   3   Donna  Carreras 3 
3    Sales   4   Janet  Gates  3 

该查询在语义上等效于:

SELECT * FROM Department e 
CROSS JOIN Employee d 
WHERE d.DepartmentID = e.DepartmentID; 

这是equabalent到:

SELECT * FROM Department e 
INNER JOIN Employee d 
ON d.DepartmentID = e.DepartmentID; 

所以,即使你有一个OUTER APPLY您的where子句把它变成一个INNER JOIN,因此与没有员工删除部门。

+0

感谢您的解释,但我也有第二个查询中的where子句..是否在子查询中的where子句的行为不同? – bmsqldev

+1

由于where子句位于子查询中,因此它首先被应用,并且不会影响从'Department'检索的行,因此而不是指示“获取部门和员工的所有组合,然后只留下部门匹配的那些”的指令,你实际上是在说“给我所有部门的记录,并为每个部门获取所有匹配的员工记录”。 – GarethD

2

您可以在部门和员工之间看到下面的计划,用于您的第一个查询外部申请。由于您的where子句,它被转换为内连接。 enter image description here

第二个查询的执行计划显示部门和员工表之间的左外连接。在第二个查询每个部门时,如果没有员工提出子查询,则检查员工将返回空值。

但在第一个含有NULL值的查询行中,由于您的where子句而被删除。

在图像'e'和'd'是employeedepartment表。

enter image description here

1

虽然你可以使用apply operator这是不是它是专为连接表。主要目的,从MSDN

APPLY运算符允许你调用一个表值函数为 由查询的外部表表达式返回的每一行。

顾名思义;表值函数是返回表的任何函数。这里有一个简单的函数:

-- Function that takes a number, adds one and returns the result. 
CREATE FUNCTION AddOne 
    (
     @StartNumber INT 
    ) 
RETURNS TABLE 
AS 
RETURN 
    (
     SELECT 
      @StartNumber + 1 AS [Result] 
    ) 
GO 

这里是一些样本数据一起玩:

-- Sample data. 
DECLARE @SampleTable TABLE 
    (
     Number INT 
    ) 
; 

INSERT INTO @SampleTable 
    (
     Number 
    ) 
VALUES 
    (1), 
    (2), 
    (3) 
; 

应用的功能,我们的桌子,就像这样:

-- Using apply. 
SELECT 
    st.Number, 
    ad.Result 
FROM 
    @SampleTable AS st 
     CROSS APPLY AddOne(st.Number) AS ad 
; 

返回:

Number Result 
1  2 
2  3 
3  4 

此博客由Robert Sheldon更详细地解释了上述内容。

的应用操作,也可以与table value constructor结合通过其他方法返回完全相同的结果:

-- Using TVC. 
SELECT 
    st.Number, 
    ad.Result 
FROM 
    @SampleTable AS st 
     CROSS APPLY 
      (
       VALUES 
        (st.Number + 1) 
      ) AS ad(Result) 
; 

这种强大的技术可以让您对您的数据进行计算,并给出结果的别名。

当涉及到应用操作符时,这个答案几乎没有划伤表面。它有更多的技巧。我强烈建议进一步研究。