OUTER在没有子查询的情况下应用

时间:2016-11-17 12:45:33

标签: sql-server tsql join sql-server-2012 outer-apply

我在SQL Server中浏览了一篇关于CROSS APPLYOUTER APPLY的文章。以下表格用于说明两者。

员工表:

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 APPLYLEFT 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

3 个答案:

答案 0 :(得分:7)

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

<option th:each="item:${list}" value="${item}">  some product $ </option>

这只是给你两张桌子的笛卡尔积:

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

现在当您在where子句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子句把它变成OUTER APPLY,从而删除没有雇员的部门。

答案 1 :(得分:2)

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

第二个查询的执行计划,显示Department和employee表之间的Left outer join。在每个部门的第二个查询中,如果没有员工在场子查询,则检查员工将返回null。

但是在第一个查询中,由于NULL子句而导致where值的行被删除。

在图像&#39; e&#39;并且&#39; d&#39;是employeedepartment表。

enter image description here

答案 2 :(得分: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的博客文章更详细地解释了上述内容。

apply运算符也可以与table value constructor结合使用,以通过其他方法返回完全相同的结果:

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

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

对于apply运算符,这个答案几乎没有触及表面。它还有很多技巧。我强烈建议进一步研究。