2009-06-04 55 views
6
就如何分割帶分隔符的字符串

我的谷歌搜索拆分逗號分隔欄導致了當字符串被稱爲分割字符串一些有用的功能:SQL 2005分隔符

SET ANSI_NULLS ON 
GO 
SET QUOTED_IDENTIFIER ON 
GO 
ALTER FUNCTION [dbo].[Split] (@String varchar(8000), @Delimiter char(1))  
    returns @temptable TABLE (items varchar(8000))  
    as  
    begin  
     declare @idx int  
     declare @slice varchar(8000)  

     select @idx = 1  
      if len(@String)<1 or @String is null return  

     while @idx!= 0  
     begin  
      set @idx = charindex(@Delimiter,@String)  
      if @idx!=0  
       set @slice = left(@String,@idx - 1)  
      else  
       set @slice = @String  

      if(len(@slice)>0) 
       insert into @temptable(Items) values(@slice)  

      set @String = right(@String,len(@String) - @idx)  
      if len(@String) = 0 break  
     end 
    return  
    end 

這像一個已知的字符串效果很好:

SELECT TOP 10 * FROM dbo.Split('This,Is,My,List',',') 

不過,我想一列傳遞給一個函數,並將它與我在它自己的行其他數據一起被聯合...例如給出的數據:

CommaColumn ValueColumn1 ValueColumn2 
----------- ------------ ------------- 
ABC,123  1    2 
XYZ, 789  2    3 

我想寫點東西像:

SELECT Split(CommaColumn,',') As SplitValue, ValueColumn1, ValueColumn2 FROM MyTable 

,並取回

SplitValue ValueColumn1 ValueColumn2 
---------- ------------ ------------ 
ABC   1    2 
123   1    2 
XYZ   2    3 
789   2    3 

這是可能的,或者有沒有人這樣做過?

+1

99%或更多的逗號分隔的列是數據庫desi不好的結果gn首先。在服務器級別上分離函數的唯一地方是將這些列重構爲它們自己的表格。 – 2009-06-04 15:52:00

+0

我希望這個表是來自你的數據庫,並且包含專有系統中的原始數據,你無法更改表格佈局? – VVS 2009-06-04 16:11:51

回答

13

是的,這可能與CROSS APPLY(SQL 2005+):

with testdata (CommaColumn, ValueColumn1, ValueColumn2) as (
    select 'ABC,123', 1, 2 union all 
    select 'XYZ, 789', 2, 3 
) 
select 
    b.items as SplitValue 
, a.ValueColumn1 
, a.ValueColumn2 
from testdata a 
cross apply dbo.Split(a.CommaColumn,',') b 

注:

  1. 你應該添加索引到結果集的分列的,所以它返回兩列,IndexNumber和Value。

  2. 帶數字表的聯機實現通常比您的程序版本快。

如:

create function [dbo].[Split] (@list nvarchar(max), @delimiter nchar(1) = N',') 
returns table 
as 
return (
    select 
    Number = row_number() over (order by Number) 
    , [Value] = ltrim(rtrim(convert(nvarchar(4000), 
     substring(@list, Number 
     , charindex(@delimiter, @[email protected], Number)-Number 
     ) 
    ))) 
    from dbo.Numbers 
    where Number <= convert(int, len(@list)) 
    and substring(@delimiter + @list, Number, 1) = @delimiter 
) 

厄蘭Sommarskog對此有明確的頁面,我認爲:http://www.sommarskog.se/arrays-in-sql-2005.html

10

修復它正確的方法 - 使該列成爲相關表格。以逗號分隔的標量列沒有任何好處。

+0

不幸的是不是我理想的情況,但仍然是正確的。 – 2009-06-04 18:26:30

0

你可以嘗試這樣的:

SELECT s.Items AS SplitValue, ValueColumn1, ValueColumn2 
FROM MyTable, Split(CommaColumn,',') AS s 
+0

這實際上可以工作..我想。 – VVS 2009-06-04 16:28:28

1

+1到反CSV的意見,但如果你必須這樣做,你會使用CROSS APPLY和OUTER APPLY。

1
alter procedure [dbo].[usp_split](@strings varchar(max)) as 
begin 
    Declare @index int 
    set @index=1 
    declare @length int 
    set @length=len(@strings) 
    declare @str varchar(max) 
    declare @diff int 
    declare @Tags table(id varchar(30)) 
    while(@index<@length) 
    begin 
     if(@index='1') 
     begin 
      set @str=(SELECT substring(@strings, @index, (charindex(',',(substring(@strings, @index,(@length)))))-1)) 
      insert into @Tags values(@str) 
       set @index=(charindex(',',(substring(@strings, @index,(@length))))) 
     end 
     else 
     begin 
      set @[email protected]@index 
      if(@diff !=0) 
      begin 
       set @str=(select substring(@strings, @index, (charindex(',',(substring(@strings,@index,@diff))))-1)) 
       if(@str is not null and @str!='') 
       begin 
        insert into @Tags VALUES(@str) 
       end 
       set @[email protected] +(charindex(',',(substring(@strings, @index,@diff)))) 
      end 
     end 
    end 
    set @str=(select right(@strings,(charindex(',',(substring(reverse(@strings),1,(@length)))))-1)) 
    insert into @Tags VALUES(@str) 
    select id from @Tags 
end 

用法:時間

exec usp_split '1212,21213,1,3,133,1313131,1,231313,5'