SQL Server 2008的cross apply 和 outer apply

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介: 我们知道有个 SQL Server 2000 中有个 cross join 是用于交叉联接的。实际上增加 cross apply 和 outer apply 是用于交叉联接表值函数(返回表结果集的函数)的, 更重要的是这个函数的参数是另一个表中的字段。

我们知道有个 SQL Server 2000 中有个 cross join 是用于交叉联接的。实际上增加
cross apply 和 outer apply 是用于交叉联接表值函数(返回表结果集的函数)的,
更重要的是这个函数的参数是另一个表中的字段。这个解释可能有些含混不请,请看下面的例子:

-- 1. cross join
联接两个表

select*
 
from TABLE_1
as
T1
crossjoin TABLE_2 as T2
-- 2. cross join
联接表和表值函数,表值函数的参数是个“常量”

select*
 
from TABLE_1
T1
crossjoin FN_TableValue(100)
-- 3. cross join  联接表和表值函数,表值函数的参数是“表T1中的字段”
select*
 
from TABLE_1
T1
crossjoin FN_TableValue(T1.column_a)

Msg
4104, Level16, State 1,
Line
1
The multi
-part identifier
"T1.column_a" could
not be bound.
最后的这个查询的语法有错误。在
crossjoin 时,表值函数的参数不能是表 T1
的字段, 为啥不能这样做呢?我猜可能微软当时没有加这个功能:),后来有客户抱怨后, 于是微软就增加了
cross apply 和
outer
apply 来完善,请看
cross apply, outer apply 的例子:


-- 4. cross apply
select*
 
from TABLE_1
T1
cross apply FN_TableValue(T1.column_a)

-- 5. outer
apply

select*
 
from TABLE_1
T1
outer apply FN_TableValue(T1.column_a)
cross apply 和
outer
apply 对于 T1 中的每一行都和派生表(表值函数根据T1当前行数据生成的动态结果集) 做了一个交叉联接。
cross apply 和
outer
apply 的区别在于: 如果根据 T1 的某行数据生成的派生表为空,
cross apply 后的结果集
就不包含 T1 中的这行数据,而
outer apply 仍会包含这行数据,并且派生表的所有字段值都为 NULL


下面的例子摘自微软 SQL Server
2005 联机帮助,它很清楚的展现了 cross apply 和
outer
apply 的不同之处:

-- cross apply
select*
 
from Departments
as
D
cross apply fn_getsubtree(D.deptmgrid) as ST
deptid     
deptname      deptmgrid   empid       empname       mgrid      
lvl
----------- -----------   ----------- -----------
-----------   ----------- ------

1           HR            2           2           Andrew        1           0
1           HR            2           5           Steven        2           1
1           HR            2           6           Michael       2           1
2           Marketing     7           7           Robert        3           0
2           Marketing     7           11          David         7           1
2           Marketing     7           12          Ron           7           1
2           Marketing     7           13          Dan           7           1
2           Marketing     7           14          James         11          2
3           Finance       8           8           Laura         3           0
4           R&D          
9           9           Ann           3           0
5           Training      4           4           Margaret      1           0
5           Training      4           10          Ina           4           1

(
12
row(s) affected)
-- outer apply
select*
 
from Departments
as
D
outer apply fn_getsubtree(D.deptmgrid) as ST
deptid     
deptname      deptmgrid   empid       empname       mgrid      
lvl
----------- -----------   ----------- -----------
-----------   ----------- ------

1           HR            2           2           Andrew        1           0
1           HR            2           5           Steven        2           1
1           HR            2           6           Michael       2           1
2           Marketing     7           7           Robert        3           0
2           Marketing     7           11          David         7           1
2           Marketing     7           12          Ron           7           1
2           Marketing     7           13          Dan           7           1
2           Marketing     7           14          James         11          2
3           Finance       8           8           Laura         3           0
4           R&D          
9           9           Ann           3           0
5           Training      4           4           Margaret      1           0
5           Training      4           10          Ina           4           1
6           Gardening     NULL       
NULL        NULL         
NULL        NULL

(
13
row(s) affected)
注意
outer apply 结果集中多出的最后一行。 当 Departments 的最后一行在进行交叉联接时:deptmgrid
NULL,fn_getsubtree(D.deptmgrid) 生成的派生表中没有数据,但 outer apply
仍会包含这一行数据,这就是它和
crossjoin 的不同之处。

下面是完整的测试代码,你可以在 SQL Server
2005 联机帮助上找到:

-- create Employees
table and insert values

IFOBJECT_ID('Employees') ISNOTNULL
DROPTABLE
Employees
GO
CREATETABLE
Employees
(
empid
INTNOTNULL,
mgrid
INTNULL,
empname
VARCHAR(25) NOTNULL,
salary
MONEYNOTNULL
)
GO
IFOBJECT_ID('Departments') ISNOTNULL
DROPTABLE
Departments
GO
-- create Departments table and insert values
CREATETABLE
Departments
(
deptid
INTNOTNULLPRIMARYKEY,
deptname
VARCHAR(25) NOTNULL,
deptmgrid
INT
)
GO

-- fill
datas

INSERT  INTO employees
VALUES 
(
1,NULL,'Nancy',00.00)
INSERT  INTO employees
VALUES 
(
2,1,'Andrew',00.00)
INSERT  INTO employees
VALUES 
(
3,1,'Janet',00.00)
INSERT  INTO employees
VALUES 
(
4,1,'Margaret',00.00)
INSERT  INTO employees
VALUES 
(
5,2,'Steven',00.00)
INSERT  INTO employees
VALUES 
(
6,2,'Michael',00.00)
INSERT  INTO employees
VALUES 
(
7,3,'Robert',00.00)
INSERT  INTO employees
VALUES 
(
8,3,'Laura',00.00)
INSERT  INTO employees
VALUES 
(
9,3,'Ann',00.00)
INSERT  INTO employees
VALUES 
(
10,4,'Ina',00.00)
INSERT  INTO employees
VALUES 
(
11,7,'David',00.00)
INSERT  INTO employees
VALUES 
(
12,7,'Ron',00.00)
INSERT  INTO employees
VALUES 
(
13,7,'Dan',00.00)
INSERT  INTO employees
VALUES 
(
14,11,'James',00.00)

INSERT  INTO departments
VALUES 
(
1,'HR',2)
INSERT  INTO departments
VALUES 
(
2,'Marketing',7)
INSERT  INTO departments
VALUES 
(
3,'Finance',8)
INSERT  INTO departments
VALUES 
(
4,'R&D',9)
INSERT  INTO departments
VALUES 
(
5,'Training',4)
INSERT  INTO departments
VALUES 
(
6,'Gardening',NULL)
GO
--SELECT * FROM
departments


-- table-value function
IFOBJECT_ID('fn_getsubtree') ISNOTNULL
DROPFUNCTION 
fn_getsubtree
GO
CREATE  FUNCTION
dbo.fn_getsubtree(
@empidASINT)
RETURNSTABLE

AS

RETURN(
 
WITH
Employees_Subtree(empid, empname, mgrid, lvl)
 
AS
  (
   
--
Anchor Member (AM)

    SELECT empid,
empname, mgrid,
0
   
FROM employees
   
WHERE
empid
=
@empid  

   
UNIONALL
   
-- Recursive Member
(RM)

    SELECT e.empid,
e.empname, e.mgrid, es.lvl
+1
   
FROM employees
AS
e
      
join employees_subtree AS es
         
ON
e.mgrid
= es.empid
  )
   
SELECT*FROM
Employees_Subtree
)
GO

-- cross apply
query

SELECT  *
FROM Departments
AS
D
   
CROSS APPLY fn_getsubtree(D.deptmgrid) AS
ST



-- outer apply query
SELECT  *
FROM Departments
AS
D
   
OUTER APPLY fn_getsubtree(D.deptmgrid) AS ST

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情: https://www.aliyun.com/product/rds/sqlserver
相关文章
|
5天前
|
SQL 人工智能 算法
【SQL server】玩转SQL server数据库:第二章 关系数据库
【SQL server】玩转SQL server数据库:第二章 关系数据库
40 10
|
1月前
|
SQL 数据库 数据安全/隐私保护
Sql Server数据库Sa密码如何修改
Sql Server数据库Sa密码如何修改
|
15天前
|
SQL
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
启动mysq异常The server quit without updating PID file [FAILED]sql/data/***.pi根本解决方案
15 0
|
5天前
|
SQL 算法 数据库
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
【SQL server】玩转SQL server数据库:第三章 关系数据库标准语言SQL(二)数据查询
55 6
|
5天前
|
SQL 存储 数据挖掘
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
服务器数据恢复环境: 一台安装windows server操作系统的服务器。一组由8块硬盘组建的RAID5,划分LUN供这台服务器使用。 在windows服务器内装有SqlServer数据库。存储空间LUN划分了两个逻辑分区。 服务器故障&初检: 由于未知原因,Sql Server数据库文件丢失,丢失数据涉及到3个库,表的数量有3000左右。数据库文件丢失原因还没有查清楚,也不能确定数据存储位置。 数据库文件丢失后服务器仍处于开机状态,所幸没有大量数据写入。 将raid5中所有磁盘编号后取出,经过硬件工程师检测,没有发现明显的硬件故障。以只读方式将所有磁盘进行扇区级的全盘镜像,镜像完成后将所
数据库数据恢复—RAID5上层Sql Server数据库数据恢复案例
|
9天前
|
SQL 安全 Java
SQL server 2017安装教程
SQL server 2017安装教程
13 1
|
22天前
|
SQL 存储 Python
Microsoft SQL Server 编写汉字转拼音函数
Microsoft SQL Server 编写汉字转拼音函数
|
1月前
|
SQL 存储 数据库
数据安全无忧,SQL Server 2014数据库定时备份解密
数据安全无忧,SQL Server 2014数据库定时备份解密
|
1月前
|
SQL 网络协议 Windows
破解SQL Server迷局,彻底解决“管道的另一端无任何进程错误233”
破解SQL Server迷局,彻底解决“管道的另一端无任何进程错误233”
|
1月前
|
SQL 数据库 数据安全/隐私保护
SQL Server的安装步骤_kaic
SQL Server的安装步骤_kaic