SQL Server數據庫操作中,在2005以上的版本新增加了一個APPLY表運算符的功能。新增的APPLY表運算符把右表表達式應用到左表表達式中的每一行。它不像JOIN那樣先計算那個表表達式都可以,APPLY必選先邏輯地計算左表達式。這種計算輸入的邏輯順序允許吧右表達式關聯到左表表達式。
APPLY有兩種形式,一個是OUTER APPLY,一個是CROSS APPLY,區別在於指定OUTER,意味著結果集中將包含使右表表達式為空的左表表達式中的行,而指定CROSS,則相反,結果集中不包含使右表表達式為空的左表表達式中的行。
理解CROSS APPLY
比如:LargeTable表中的某一列存儲的數據是以“:”號分隔的數據,我們處理的時候,可能要先把這個值,先分隔,然後把分隔後的每個值單獨一行放在一張表中,然後對這個表做處理。這只是用其中一行做的處理,如果我們把表中多行都做這樣的處理,把多行以:號分隔的數值都放在一個表中,該怎麼處理呢?
用APPLY表運算符一行語句就能處理以上操作。
復制代碼 代碼如下:
SELECT
a
FROM
dbo.LargeTable AS LT --實際表
CROSS APPLY
dbo.Split(LT.Name,':') --自定義表值函數,完成字符串分隔
WHERE
a <> '' --去掉結果表中a字段為空的數據
-----------字符串分隔函數-------------
CREATE Function [dbo].[Split]
(
@Sql varchar(8000),
@Splits varchar(10)
)
returns @temp Table (a varchar(100))
As
Begin
Declare @i Int
Set @Sql = RTrim(LTrim(@Sql))
Set @i = CharIndex(@Splits,@Sql)
While @i >= 1
Begin
Insert @temp Values(Left(@Sql,@i-1))
Set @Sql = SubString(@Sql,@i+1,Len(@Sql)-@i)
Set @i = CharIndex(@Splits,@Sql)
End
If @Sql <> ''
Insert @temp Values (@Sql)
Return
End
------------調用示例-------------
SELECT
*
FROM
dbo.Split('581::579::519::279::406::361::560',':')
APPLY的執行過程:它先邏輯計算左表表達式,然後把右表達式應用到左表表達式的每一行。實際是把外部查詢的列引用作為參數傳遞給表值函數。
我們知道 SQL Server2000 中有個 cross join 是用於交叉聯接的。實際上SQL Server 2005 新增 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 query
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)
----------- ----------- ----------- ----------- ----------- ----------- ------
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)