关于Cross Join 和 Outer/Cross Apply
目录
先为大家准备点数据:
CREATE TABLE TA(Acol INT);
GO
INSERT INTO TA
SELECT 1 UNION ALL
SELECT 2;
GO
CREATE TABLE TB(Bcol1 INT,Bcol2 VARCHAR(10));
GO
INSERT INTO TB
SELECT -1, 'a' UNION ALL
SELECT 1, 'b' UNION ALL
SELECT 3, 'c';
GO
1. Cross Join
Cross Join,交叉联接,其实就是笛卡尔积。
select * from TA cross join TB
或
select * from TA,TB
的结果是一样的:
2. Cross / Outer Apply
请看下面这条语句:
select * from TA a cross apply (select * from TB where Bcol1=a.Acol) b
结果是:
是不是觉得很眼熟,是的,上面的语句和
select * from TA a inner join TB b on a .Acol = b .Bcol1
是一样的,甚至执行计划都是一样的,上面的语句完全按照inner join的思路去执行。
再看用outer apply:
select * from TA a outer apply (select * from TB where Bcol1=a.Acol) b
结果是:
是不是依然很眼熟,没错,它和
select * from TA a left join TBb on a .ACol = b .BCol1
是一样的。执行计划依然一样,上面的语句按left join的思路去执行。
既然这样,为什么还要多出一个Cross/Outer Apply呢?
3. Cross / Outer Apply的专属功能
测试数据:
CREATE TABLE tmp([str] VARCHAR(100))
GO
INSERT INTO tmp
SELECT 'I@@Love@@Coding' UNION ALL
SELECT 'This@@is@@it'
GO
假设现在有一个需求,将tmp中每一行都以@@作为分隔符拆分为列表,然后与拆分前的那一行作交叉联接(笛卡尔积)。
拆分函数网上有很多,为了节省篇幅就不放代码了,可以到我另一篇博文中看。假设此拆分函数为dbo.f_Split(@str varchar(1000),@delimiter varchar(100) = ’’ ),@str为源字符串,@delimiter为分隔符。先用常量作为函数参数来理解一下上面所说的需求:
select * from TA cross join dbo.f_Split('Xiao;;Ming',';;')
或
select * from TA,dbo.f_Split('Xiao;;Ming',';;')
结果:
可以看到TA中的行和表值函数返回的表作了联接。上面的cross join就可以做到。再看一下用表中的列作函数参数:
select * from tmp a cross Join dbo.f_Split(a.[str],'@@')b
结果是报错:
现在Cross Apply 的作用就真正体现出来了:
select * from tmp a cross apply dbo.f_Split(a.[str],'@@') b
结果: