2009-06-04 2 views
6

Мои Google поиск о том, как разбить строку на разделитель, привели некоторые полезные функции для разделения строк, когда строка известна (т.е. ниже):SQL 2005 Split, разделенные запятыми Колонка ограничителем

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',',') 

Однако, я хотел бы передать столбец в функцию, и он unioned вместе с другими моими данными в его собственном ряду ... например, с учетом данных :

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 в первую очередь. Единственное место для функции split на уровне сервера - это реорганизация этих столбцов в их собственную таблицу. –

+0

Надеюсь, что эта таблица находится в вашей промежуточной базе данных и содержит необработанные данные из запатентованной системы, где у вас нет возможности изменить раскладку таблицы? – VVS

ответ

13

Да, это возможно с CROSS ОТНОСИТЬСЯ (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 
) 

Erland Sommarskog имеет окончательную страницу на это, я думаю: http://www.sommarskog.se/arrays-in-sql-2005.html

+0

Excelent Питер.Сэкономил у меня много неприятностей :) –

10

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

+0

К сожалению, не моя идеальная ситуация, но тем не менее все же исправлена. –

0

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

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

Это могло на самом деле работать .. думаю. – VVS

+0

Ugh, плохой синтаксис соединения тоже. –

+0

Пробовал это, что, к сожалению, не сработало .. спасибо за вашу попытку. –

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' 
Смежные вопросы