Cross Apply的用法


GPS平台、網站建設、軟件開發、系統運維,找森大網絡科技!
https://cnsendnet.taobao.com
來自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=2029

 

透過執行計划可以看出,cross apply類似不帶where條件的連接即cross join 。形式上會靈活些.  
使用 APPLY 運算符可以為實現查詢操作的外部表表達式返回的每個行調用表值函數。表值函數作為右輸入,外部表表達式作為左輸入
。通過對右輸入求值來獲得左輸入每一行的計算結果,生成的行被組合起來作為最終輸出。APPLY 運算符生成的列的列表是左輸入中
的列集,后跟右輸入返回的列的列表。
APPLY 有兩種形式: CROSS APPLY 和 OUTER APPLY。CROSS APPLY 僅返回外部表中通過表值函數生成結果集的行。OUTER APPLY 既返
回生成結果集的行,也返回不生成結果集的行,其中表值函數生成的列中的值為 NULL。

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 的不同之處。

 

    1. 小例子一

cross apply的經典用法;求每個人考試科目中成績的前兩名(取出每組中的前幾名)

 

  1. 疑問

USE tempdb

GO

 

-- 用於分拆字符串的表值函數

CREATE FUNCTION dbo.f_Split(

    @str varchar(max)

)RETURNS @re TABLE(

        id int IDENTITY, val varchar(10))

AS

BEGIN

    DECLARE @pos int

    SET @pos = CHARINDEX(',', @str)

    WHILE @pos > 0

    BEGIN

        INSERT @re(val) VALUES(LEFT(@str, @pos - 1))

        SELECT

            @str = STUFF(@str, 1, @pos, ''),

            @pos = CHARINDEX(',', @str)

    END

    IF @str > ''

        INSERT @re(val) VALUES(@str)

    RETURN

END

GO

 

-- 用於分拆的示例數據

DECLARE @tb TABLE(

    col varchar(max))

INSERT @tb

SELECT col = '1,2,3' UNION ALL

SELECT col = NULL UNION ALL

SELECT col = '' UNION ALL

SELECT col = '1'

 

-- 使用 CROSS APPLY

SELECT *

FROM @tb A

    CROSS APPLY dbo.f_Split(A.col) B

 

-- 使用 OUTER APPLY

SELECT *

FROM @tb A

    OUTER APPLY dbo.f_Split(A.col) B

GO

 

-- 刪除演示數據

DROP FUNCTION dbo.f_Split

/*

(4 行受影響)

col                                                                                                                                                                                                                                                              id          val

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------- ----------

1,2,3                                                                                                                                                                                                                                                            1           1

1,2,3                                                                                                                                                                                                                                                            2           2

1,2,3                                                                                                                                                                                                                                                            3           3

1                                                                                                                                                                                                                                                                1           1

 

(4 行受影響)

 

col                                                                                                                                                                                                                                                              id          val

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------- ----------

1,2,3                                                                                                                                                                                                                                                            1           1

1,2,3                                                                                                                                                                                                                                                            2           2

1,2,3                                                                                                                                                                                                                                                            3           3

NULL                                                                                                                                                                                                                                                             NULL        NULL

                                                                                                                                                                                                                                                                 NULL        NULL

1                                                                                                                                                                                                                                                                1           1

 

(6 行受影響)

 

*/

 

GPS平台、網站建設、軟件開發、系統運維,找森大網絡科技!
https://cnsendnet.taobao.com
來自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=2029


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM