T-SQL Part VIII: CROSS APPLY, OUTER APPLY

除了CROSS JOIN, INNER JOIN, OUTER JOIN之外,T-SQL還提供了CROSS APPLY和OUTER APPLY這兩個較爲另類的Set操作符。

首先來看CROSS APPLY。跟CROSS JOIN一樣,MSDN只在FROM Clause的文檔中做了一個介紹,如下:

Both the left and right operands of the APPLY operator are table expressions. The main difference between these operands is that the right_table_source can use a table-valued function that takes a column from the left_table_source as one of the arguments of the function. The left_table_source can include table-valued functions, but it cannot contain arguments that are columns from the right_table_source.

The APPLY operator works in the following way to produce the table source for the FROM clause:
Evaluates right_table_source against each row of the left_table_source to produce rowsets.
The values in the right_table_source depend on left_table_source. right_table_source can be represented approximately this way: TVF(left_table_source.row), where TVF is a table-valued function.
Combines the result sets that are produced for each row in the evaluation of right_table_source with the left_table_source by performing a UNION ALL operation.

The list of columns produced by the result of the APPLY operator is the set of columns from the left_table_source that is combined with the list of columns from the right_table_source.

簡單來說就是,APPLY操作符的過程就是:

  1. 計算左表表達式
  2. 將左表表達式結果作爲右表輸入

通常,對右表表達式,即可以是表,也可以爲Function。

例一,右表表達式爲Function,左表中名爲Tags的Column保存了多個Key拼接而成的字符串。如Tags爲“abc, def, acd”

-- Define functions
if object_id('parsetags','TF') is not null
drop function parsetags;
GO
create function parsetags(
    @tags nvarchar(1000),
    @splits varchar(10) 
)
returns @t_tags TABLE (tag nvarchar(100))
as
begin
  set @tags = RTrim(LTrim(@tags)) 
  set @i = CharIndex(@splits,@tags) 

  while @i >= 1 
  begin 
    insert @t_tags Values(Left(@tags,@i-1)) 
    set @tags = SubString(@tags,@i+1,Len(@tags)-@i) 
    set @i = CharIndex(@Splits,@tags) 
  end 

  if @tags <> '' 
  insert @t_tags Values (@tags) 
  return;
end
GO

-- Define table t_blog
CREATE TABLE t_blog
( 
    blogid INT NOT NULL, 
    blogcontent NVARCHAR(MAX) NOT NULL,
    tags NVARCHAR(200) NOT NULL
) 
GO 

-- Example of CROSS APPLY
SELECT * FROM t_blog CROSS APPLY parsetags(t_blog.tags, ';')
GO

例二,右表表達式爲另外一張表,選出每個Customer最大的兩筆Sales訂單。

-- Create Customer table
CREATE TABLE t_customer
( 
    [id] NVARCHAR(50) NOT NULL, 
    [name] NVARCHAR(50) NOT NULL
) 
GO 

-- Create Sales table
CREATE TABLE t_sales
( 
    [id] NVARCHAR(50) NOT NULL, 
    [custid] NVARCHAR(50) NOT NULL,
    [amount] MONEY NOT NULL
) 
GO

-- Using cross apply
SELECT t_customer.[id] as custid, t_customer.[name] as custname, sales.[id] as saleid, sales.[amount] as salesamount 
FROM t_customer
CROSS APPLY 
(SELECT top 2 * 
    FROM t_sales
    WHERE t_customer.id = t_sales.custid
    ORDER BY amount) AS sales
GO

以上都是使用CROSS APPLY做例子,而OUTER APPLY與其的主要區別是,OUTER APPLY會左表表達式中存在而右表表達式運算結果爲NULL的項目,跟INNER JOIN跟OUTER JOIN的概念完全一致。

用例二作爲說明:

  • 使用CROSS APPLY時,沒有任何Sales的Customer在結果集中不顯示;
  • 用OUTER APPLY時,沒有Sales的Customer也會在結果集中出現,但其對應的saleid和saleamount都爲NULL

是爲之記。
Alva Chien
2016.6.14

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章