Разделенный запятыми столбец SQL 2005 на разделителе - PullRequest
6 голосов
/ 04 июня 2009

Мой поиск в Google о том, как разделить строку по разделителю, привел к некоторым полезным функциям для разделения строк, когда строка известна (т.е. см. Ниже):

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

Возможно ли это, или кто-то делал это раньше?

Ответы [ 5 ]

13 голосов
/ 04 июня 2009

Да, это возможно с 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, @list+@delimiter, Number)-Number
        )
    )))
  from dbo.Numbers
  where Number <= convert(int, len(@list))
    and substring(@delimiter + @list, Number, 1) = @delimiter
  )

У Эрланда Соммарскога есть определенная страница по этому вопросу, я думаю: http://www.sommarskog.se/arrays-in-sql-2005.html

10 голосов
/ 04 июня 2009

Исправьте это правильно - сделайте этот столбец связанной таблицей. Нет ничего хорошего в скалярных столбцах, разделенных запятыми.

1 голос
/ 24 июля 2012
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 @diff=@length-@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 @index=@index +(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'
1 голос
/ 04 июня 2009

+ 1 к комментариям анти-CSV, но если вы должны сделать это, вы бы использовали CROSS APPLY или OUTER APPLY.

0 голосов
/ 04 июня 2009

Вы можете попробовать что-то вроде:

SELECT s.Items AS SplitValue, ValueColumn1, ValueColumn2 
FROM MyTable, Split(CommaColumn,',') AS s
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...