2009-06-04 11 views
6

My Google wyszukiwania, w jaki sposób podzielić ciąg separatora doprowadziły w niektórych przydatnych funkcji ciągów przecinania gdy ciąg jest znany (czyli patrz poniżej):SQL 2005 Podział oddzielone przecinkami Column na ogranicznik

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 

działa to dobrze znany ciąg jak:

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

jednak chciałbym przekazać kolumny do funkcji i mieć ona unioned razem z moimi innymi danymi w jego własnym rzędzie ... na przykład biorąc pod uwagę dane :

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

Chciałbym napisać coś takiego:

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

i wrócić

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

Czy to możliwe, lub czy ktoś zrobił to wcześniej?

+1

99% czasu lub więcej kolumn oddzielonych przecinkiem jest wynikiem złych baz danych desi gn w pierwszej kolejności. Jedynym miejscem dla funkcji podziału na poziomie serwera jest refaktoryzacja tych kolumn w ich własnej tabeli. –

+0

Mam nadzieję, że ta tabela pochodzi z bazy danych i zawiera surowe dane z zastrzeżonego systemu, w którym nie ma możliwości zmiany układu tabeli? – VVS

Odpowiedz

13

Tak, jest to możliwe z 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 

Uwagi:

  1. Należy dodać indeks do zestawu wyników swojej dzielonej kolumny, tak że zwraca dwie kolumny, IndexNumber i Value.

  2. In-line wdrożenia z tabelą numerów są na ogół szybsze niż tutaj.

np

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 
) 

Erland Sommarskog ma ostateczne stronę na ten temat, myślę: http://www.sommarskog.se/arrays-in-sql-2005.html

+0

Doskonały Peter.Uratowałem mój ** od wielu kłopotów :) –

10

Napraw to właściwy sposób - ustaw tę kolumnę jako powiązaną tabelę. Nic dobrego nigdy nie nadejdzie z kolumnami skalarnymi oddzielonymi przecinkami.

+0

Niestety nie moja idealna sytuacja, ale mimo to poprawna. –

0

Można spróbować czegoś takiego:

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

To może faktycznie zadziałać .. Myślę. – VVS

+0

Ugh, zła składnia również. –

+0

Próbowałem tego, co niestety nie zadziałało .. dziękuję za twoją próbę. –

1

+1 do anty-CSV komentarze, ale jeśli trzeba to zrobić należałoby użyć CROSS APPLY lub zewnętrznym Zastosuj.

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 

Zastosowanie:

exec usp_split '1212,21213,1,3,133,1313131,1,231313,5' 
Powiązane problemy