不带子查询的外部应用
OUTER apply without subquery
我在 SQL 服务器中浏览了一篇关于 CROSS APPLY
和 OUTER APPLY
的文章。以下 table 用于说明两者。
员工table:
EmployeeID FirstName LastName DepartmentID
1 Orlando Gee 1
2 Keith Harris 2
3 Donna Carreras 3
4 Janet Gates 3
部门table:
DepartmentID Name
1 Engineering
2 Administration
3 Sales
4 Marketing
5 Finance
我知道 OUTER APPLY
类似于 LEFT OUTER JOIN.
但是当我在 table 之间应用 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
当我在 table 之间应用 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
吗?
我认为理解这一点的关键是查看此查询的输出:
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 APPLY
,您的 where 子句也会将其变成 INNER JOIN
,从而删除没有员工的部门。
您可以在下面看到您的第一个查询在 Department 和 employee 之间应用的计划。由于您的 where
子句,它被转换为内部连接。
第二个查询的执行计划显示部门和员工之间的左外连接 table。在您对每个部门的第二个查询中,如果没有员工在场,您的检查员工子查询将 return 为空。
但是在第一个查询中,由于您的 where
子句,具有 NULL
值的行被删除了。
图中'e'和'd'分别是employee
和department
tables.
尽管您可以使用 apply operator this is not what it was designed for. The primary purpose, from MSDN:
加入 tables
The APPLY operator allows you to invoke a table-valued function for
each row returned by an outer table expression of a query.
顾名思义; table 值函数是 return 是 table 的任何函数。这是一个简单的函数:
-- 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)
;
将函数应用到我们的 table,像这样:
-- Using apply.
SELECT
st.Number,
ad.Result
FROM
@SampleTable AS st
CROSS APPLY AddOne(st.Number) AS ad
;
Returns:
Number Result
1 2
2 3
3 4
Robert Sheldon 的这篇博文更详细地解释了上述内容。
apply 运算符也可以与 table value constructor 结合使用另一种方法 return 完全相同的结果:
-- Using TVC.
SELECT
st.Number,
ad.Result
FROM
@SampleTable AS st
CROSS APPLY
(
VALUES
(st.Number + 1)
) AS ad(Result)
;
这项强大的技术允许您对数据执行计算,并为结果指定别名。
当涉及到应用运算符时,这个答案几乎没有触及表面。它有更多的技巧。我强烈建议进一步研究。
我在 SQL 服务器中浏览了一篇关于 CROSS APPLY
和 OUTER APPLY
的文章。以下 table 用于说明两者。
员工table:
EmployeeID FirstName LastName DepartmentID
1 Orlando Gee 1
2 Keith Harris 2
3 Donna Carreras 3
4 Janet Gates 3
部门table:
DepartmentID Name
1 Engineering
2 Administration
3 Sales
4 Marketing
5 Finance
我知道 OUTER APPLY
类似于 LEFT OUTER JOIN.
但是当我在 table 之间应用 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
当我在 table 之间应用 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
吗?
我认为理解这一点的关键是查看此查询的输出:
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 APPLY
,您的 where 子句也会将其变成 INNER JOIN
,从而删除没有员工的部门。
您可以在下面看到您的第一个查询在 Department 和 employee 之间应用的计划。由于您的 where
子句,它被转换为内部连接。
第二个查询的执行计划显示部门和员工之间的左外连接 table。在您对每个部门的第二个查询中,如果没有员工在场,您的检查员工子查询将 return 为空。
但是在第一个查询中,由于您的 where
子句,具有 NULL
值的行被删除了。
图中'e'和'd'分别是employee
和department
tables.
尽管您可以使用 apply operator this is not what it was designed for. The primary purpose, from MSDN:
加入 tablesThe APPLY operator allows you to invoke a table-valued function for each row returned by an outer table expression of a query.
顾名思义; table 值函数是 return 是 table 的任何函数。这是一个简单的函数:
-- 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)
;
将函数应用到我们的 table,像这样:
-- Using apply.
SELECT
st.Number,
ad.Result
FROM
@SampleTable AS st
CROSS APPLY AddOne(st.Number) AS ad
;
Returns:
Number Result
1 2
2 3
3 4
Robert Sheldon 的这篇博文更详细地解释了上述内容。
apply 运算符也可以与 table value constructor 结合使用另一种方法 return 完全相同的结果:
-- Using TVC.
SELECT
st.Number,
ad.Result
FROM
@SampleTable AS st
CROSS APPLY
(
VALUES
(st.Number + 1)
) AS ad(Result)
;
这项强大的技术允许您对数据执行计算,并为结果指定别名。
当涉及到应用运算符时,这个答案几乎没有触及表面。它有更多的技巧。我强烈建议进一步研究。