先說點題外話,因為後面我會用到這個函數。 前兩天自定義了一個 sql 的字元串分割函數(Split),不過後來發現有點問題,例如: 我之前只處理了截取的最後一個為空的字元串,所以會出現以上的結果,現在我做了一些修改。代碼如下: 紅色部分的代碼為添加或修改的部分,下麵再看一下效果。 之前自定義 Spl ...
先說點題外話,因為後面我會用到這個函數。
前兩天自定義了一個 sql 的字元串分割函數(Split),不過後來發現有點問題,例如:
1 select * from Split(default,'123,456,,,,789,')
我之前只處理了截取的最後一個為空的字元串,所以會出現以上的結果,現在我做了一些修改。代碼如下:
1 USE [Test] 2 GO 3 /****** Object: UserDefinedFunction [dbo].[Split] Script Date: 2017/4/16 22:05:35 ******/ 4 SET ANSI_NULLS ON 5 GO 6 SET QUOTED_IDENTIFIER ON 7 GO 8 ALTER FUNCTION [dbo].[Split](@separator VARCHAR(64)=',',@string NVARCHAR(max)) 9 RETURNS @ResultTab TABLE ( 10 Id INT , 11 Res NVARCHAR(500) 12 ) 13 AS 14 BEGIN 15 DECLARE @Num INT 16 DECLARE @Str nvarchar(500) 17 18 IF(@string IS NOT NULL AND @string <> '' AND LEN(@string)>0) 19 BEGIN 20 IF(CHARINDEX(@separator,@string)>0) --判斷要截取的字元是否存在 21 BEGIN 22 SET @Num=0 23 WHILE (CHARINDEX(@separator,@string)>0) --如果要截取的字元存在,就繼續迴圈 24 BEGIN 25 SET @Num=@Num+1 26 set @Str=LEFT(@string,CHARINDEX(@separator,@string)-1) 27 28 if(@Str is not null and @Str <> '') --做一下判斷,如果截取的字元串為空就不插入返回結果的表 29 begin 30 INSERT INTO @ResultTab(Id,Res) --截取字元串,插入表變數 31 SELECT @Num,@Str 32 end 33 else 34 begin 35 set @Num=@Num-1 36 end 37 38 --把已經截取並插入的字元串刪除 39 SET @string=STUFF(@string,1,CHARINDEX(@separator,@string)-1+LEN(@separator),'') 40 END 41 42 --如果最後一個截取的字元串為空,那就不插入了 43 --例如:'123,456,789,' 這樣的字元串最後剩下的就是空字元串了 44 IF(@string IS NOT NULL AND @string <> '') 45 BEGIN 46 INSERT INTO @ResultTab(Id,Res) 47 SELECT @Num+1,@string 48 END 49 END 50 ELSE 51 BEGIN 52 DELETE FROM @ResultTab 53 END 54 END 55 ELSE 56 BEGIN 57 DELETE FROM @ResultTab 58 END 59 RETURN 60 END
紅色部分的代碼為添加或修改的部分,下麵再看一下效果。
1 select * from Split(default,'123,456,,,,789,321,,,')
之前自定義 Split 函數時我還覺得不能直接作用於表,不過今天瞭解到一個方法,讓我覺得或許可以實現。
APPLY 運算符:
使用 APPLY 運算符(2005或以上版本)可以為實現查詢操作的外部表表達式返回的每個行調用表值函數。表值函數作為右輸入,外部表表達式作為左輸入。通過對右輸入求值來獲得左輸入每一行的計算結果,生成的行被組合起來作為最終輸出。APPLY 運算符生成的列的列表是左輸入中的列集,後跟右輸入返回的列的列表。
APPLY 有兩種形式: CROSS APPLY 和 OUTER APPLY。CROSS APPLY 僅返回外部表中通過表值函數生成結果集的行。OUTER APPLY 既返回生成結果集的行,也返回不生成結果集的行,其中表值函數生成的列中的值為 NULL。
語法:
<left_table_expression> {cross|outer} apply <right_table_expression>
先看看示例所用的數據:
現在有兩個表,一個用戶信息表和一個操作許可權表,下麵通過示例看看 apply 運算符有什麼作用。
CROSS APPLY :
1 select * from UserInfo u 2 cross apply dbo.Split(default,u.P_Id)
最後兩列為使用 cross apply 連接表值函數 Split 分割欄位 P_Id 的值。下麵如果我們要查詢操作許可權的名稱呢?
1 select t.U_Id,t.U_No,t.U_Name,t.U_Pwd,t.P_Id,p.P_Id,p.P_Name,p.P_Remark from ( 2 select * from UserInfo u 3 cross apply dbo.Split(default,u.P_Id))t 4 left join OperatePower p on t.Res=p.P_Id
OUTER APPLY:
1 select * from UserInfo u 2 outer apply dbo.Split(default,u.P_Id) 3 4 select t.U_Id,t.U_No,t.U_Name,t.U_Pwd,t.P_Id,p.P_Id,p.P_Name,p.P_Remark from ( 5 select * from UserInfo u 6 outer apply dbo.Split(default,u.P_Id))t 7 left join OperatePower p on t.Res=p.P_Id
可以看到 OUTER APPLY 返回的數據比 CORSS APPLY 返回的數據要多一行,這是因為,CORSS APPLY 只是返回能夠匹配上的,而 OUTER APPLY 會返回所有的,不管能不能匹配上,不能匹配的就返回空(null)。
當然,OUTER APPLY 和 CORSS APPLY 還可以作用於表之間的連接:
1 create table #T(姓名 varchar(10)) 2 insert into #T values('張三') 3 insert into #T values('李四') 4 insert into #T values(NULL ) 5 6 7 create table #T2(姓名 varchar(10) , 課程 varchar(10) , 分數 int) 8 insert into #T2 values('張三' , '語文' , 74) 9 insert into #T2 values('張三' , '數學' , 83) 10 insert into #T2 values('張三' , '物理' , 93) 11 insert into #T2 values(NULL , '數學' , 50) 12 13 14 select * from #T a 15 cross apply (select 課程,分數 from #t2 where 姓名=a.姓名) b 16 17 select * from #T a 18 outer apply (select 課程,分數 from #t2 where 姓名=a.姓名) b
參考:
http://www.cnblogs.com/qixuejia/p/3960904.html