您的位置:首页 > 移动开发

關於Cross Join 和 Outer/Cross Apply

2013-11-23 10:22 316 查看
先為大家準備點數據:

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 TBb
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 ona.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

 結果:



4.   小結

1)      Cross Join就是笛卡爾積;

2)      在不涉及到表值函數的情況下,Cross Apply  和 Outer Apply所起的作用與Inner
Join 和 Left Join 一樣,所以一般情況下不要用Apply,這樣反而容易造成不易理解的負面效應;

3)      Cross / Outer Apply可以說完全為表值函數而生,支持了表的每一行和由此行中數據作爲參數去調用表值函數而返回的結果表作交叉連接(類笛卡爾積)。看MSDN的介紹Apply的文檔,沒有一個實例沒有用到表值函數(TF)的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: