Sql server 不带子查询的外部应用

Sql server 不带子查询的外部应用,sql-server,tsql,join,sql-server-2012,outer-apply,Sql Server,Tsql,Join,Sql Server 2012,Outer Apply,我读了一篇关于SQL Server中的交叉应用和外部应用的文章。下表用于说明这两种情况 员工表: EmployeeID FirstName LastName DepartmentID 1 Orlando Gee 1 2 Keith Harris 2 3 Donna Carreras 3 4 Janet Gates 3

我读了一篇关于SQL 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
我知道
外部应用
类似于
左外部连接。
但当我在下表之间应用
外部应用

select * from Department e
outer apply
Employee d
where d.DepartmentID = e.DepartmentID
我得到了以下结果(与
内部连接
结果相同)

当我应用
OUTER时,在如下表之间应用
(将
右表
作为子查询)

我得到了以下结果(与
左外连接
结果相同)


有人能解释为什么这两个查询给出了不同的
输出吗?

我认为理解这一点的关键是看到这个查询的输出:

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子句
中重新添加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;

因此,即使您有一个
外部应用
语句,您的where子句也会将其转换为
内部联接
,从而删除没有员工的部门。

您可以看到下面的第一个查询计划:部门和员工之间的外部应用。由于您的
where
子句,它被转换为内部联接。

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

但是在第一个查询中,由于
where
子句,具有
NULL
值的行被删除

图中的“e”和“d”是
员工
部门
表格


尽管您可以使用连接表,但这不是它的设计目的。主要目的是:

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
作者的这篇博客文章更详细地解释了上述内容

应用运算符还可以与组合,以通过另一种方法返回完全相同的结果:

-- Using TVC.
SELECT
    st.Number,
    ad.Result
FROM
    @SampleTable AS st
        CROSS APPLY 
            (
                VALUES  
                    (st.Number + 1)
            ) AS ad(Result)
;
这项功能强大的技术允许您对数据执行计算,并为结果提供别名


当涉及到应用操作符时,这个答案几乎没有触及表面。它还有很多妙招。我强烈建议进一步研究。

谢谢您的解释,但我在第二次查询中也有where子句。where子句在子查询中的行为是否不同?因为where子句在子查询中,它是首先应用的,并且不会影响从
部门
检索到的行,因此,与“获取部门和员工的所有组合,然后只保留部门匹配的组合”不同,您实际上是说“从部门获取所有记录,并为每个部门获取所有匹配的员工记录”。
-- 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
-- Using TVC.
SELECT
    st.Number,
    ad.Result
FROM
    @SampleTable AS st
        CROSS APPLY 
            (
                VALUES  
                    (st.Number + 1)
            ) AS ad(Result)
;