4

我浏览了一篇关于CROSS APPLYOUTER APPLYSQL Server下表用于说明两者。

员工表:

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

我得到以下结果(与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吗?

4

3 回答 3

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;

这相当于:

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

因此,即使您有OUTER APPLYwhere 子句将其转换为INNER JOIN,从而删除没有员工的部门。

于 2016-11-17T12:53:45.923 回答
2

您可以看到下面的计划,用于部门和员工之间的第一个查询外部应用。由于您的where子句,它被转换为内部连接。 在此处输入图像描述

以及显示部门和员工表之间的左外连接的第二个查询的执行计划。在您对每个部门的第二个查询中,如果没有员工存在子查询,您的检查员工将返回 null。

但是在第一个查询中,NULL由于您的where子句,带有值的行被消除了。

在图像“e”和“d”中是employeedepartment表格。

在此处输入图像描述

于 2016-11-17T12:55:42.887 回答
1

虽然您可以使用apply 运算符连接表,但这不是它的设计目的。主要目的,来自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的这篇博客文章更详细地解释了上述内容。

apply 运算符还可以与表值构造函数结合使用,以通过另一种方法返回完全相同的结果:

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

这种强大的技术允许您对数据执行计算,并给结果一个别名。

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

于 2016-11-17T13:45:20.123 回答