Sql server 不带子查询的外部应用
我读了一篇关于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
交叉应用
和外部应用
的文章。下表用于说明这两种情况
员工表:
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)
;