设为首页 收藏本站
查看: 3484|回复: 0

[经验分享] SQL Server 2005 中 Cross Apply & Outer Apply

[复制链接]

尚未签到

发表于 2016-11-5 01:35:22 | 显示全部楼层 |阅读模式
  SQL Server 2005 新增 cross apply 和 outer apply 联接语句,增加这两个东东有啥作用呢?
  我们知道有个 SQL Server 2000 中有个 cross join 是用于交叉联接的。实际上增加 cross apply 和 outer apply 是用于交叉联接表值函数(返回表结果集的函数)的, 更重要的是这个函数的参数是另一个表中的字段。这个解释可能有些含混不请,请看下面的例子:

-- 1. cross join 联接两个表
select *
from TABLE_1 as T1
cross join TABLE_2 as T2

-- 2. cross join 联接表和表值函数,表值函数的参数是个“常量”
select *
from TABLE_1 T1
cross join FN_TableValue(100)

-- 3. cross join  联接表和表值函数,表值函数的参数是“表T1中的字段”
select *
from TABLE_1 T1
cross join FN_TableValue(T1.column_a)
Msg 4104, Level 16, State 1, Line 1
The multi-part identifier "T1.column_a" could not be bound.

  最后的这个查询的语法有错误。在 cross join 时,表值函数的参数不能是表 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 仍会包含这一行数据,这就是它和 cross join 的不同之处。
  下面是完整的测试代码,你可以在 SQL Server 2005 联机帮助上找到:

-- create Employees table and insert values
create table Employees
(
empid   int         not null,
mgrid   int         NULL,
empname varchar(25) not null,
salary  money       not null
)
go

-- create Departments table and insert values
create table Departments
(
deptid    int not null primary key,
deptname  varchar(25) not null
)
go
-- fill datas
insert into employees values(1 , NULL, 'Nancy'   , 000.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

-- table-value function
create function dbo.fn_getsubtree(@empid AS INT) returns @TREE table
(
empid   int not null,
empname varchar(25) not null,
mgrid   int null,
lvl     int not null
)
as
begin
with Employees_Subtree(empid, empname, mgrid, lvl)
as
(
-- Anchor Member (AM)
select empid, empname, mgrid, 0
from employees
where empid = @empid
union all
-- 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
)

insert into @TREE
select * from Employees_Subtree
return
end
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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-295731-1-1.html 上篇帖子: sql server 2005中新增的bulk功能 下篇帖子: Sql Server日期格式的转换收集(转)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表