SQL Server 2008的cross apply 和 outer apply

本文涉及的产品
云数据库 RDS SQL Server,基础系列 2核8GB
简介: 我们知道有个 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

相关文章
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
541 13
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
363 9
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
262 6
|
SQL
SQL FULL OUTER JOIN 关键字
【7月更文挑战第17天】SQL FULL OUTER JOIN 关键字。
195 6
|
SQL Oracle 关系型数据库
MySQL、SQL Server和Oracle数据库安装部署教程
数据库的安装部署教程因不同的数据库管理系统(DBMS)而异,以下将以MySQL、SQL Server和Oracle为例,分别概述其安装部署的基本步骤。请注意,由于软件版本和操作系统的不同,具体步骤可能会有所变化。
1182 3
|
存储 SQL C++
对比 SQL Server中的VARCHAR(max) 与VARCHAR(n) 数据类型
【7月更文挑战7天】SQL Server 中的 VARCHAR(max) vs VARCHAR(n): - VARCHAR(n) 存储最多 n 个字符(1-8000),适合短文本。 - VARCHAR(max) 可存储约 21 亿个字符,适合大量文本。 - VARCHAR(n) 在处理小数据时性能更好,空间固定。 - VARCHAR(max) 对于大文本更合适,但可能影响性能。 - 选择取决于数据长度预期和业务需求。
1171 1
|
SQL 存储 安全
数据库数据恢复—SQL Server数据库出现逻辑错误的数据恢复案例
SQL Server数据库数据恢复环境: 某品牌服务器存储中有两组raid5磁盘阵列。操作系统层面跑着SQL Server数据库,SQL Server数据库存放在D盘分区中。 SQL Server数据库故障: 存放SQL Server数据库的D盘分区容量不足,管理员在E盘中生成了一个.ndf的文件并且将数据库路径指向E盘继续使用。数据库继续运行一段时间后出现故障并报错,连接失效,SqlServer数据库无法附加查询。管理员多次尝试恢复数据库数据但是没有成功。
|
SQL 安全 Java
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。错误:“The server selected protocol version TLS10 is not accepted by client
1370 0
|
SQL 监控 数据库
SQL Server 查询超时问题排查
【7月更文挑战第8天】排查 SQL Server 查询超时涉及五个主要方面:检查复杂查询、评估服务器性能、审视配置参数、更新统计信息和分析执行计划。关注点包括查询的结构(如连接、子查询和索引),服务器资源(CPU、内存、网络延迟),连接和内存设置,以及统计信息的时效性。通过这些步骤可定位并解决性能瓶颈。
553 0