2009-06-04 50 views
6

My Google búsquedas en cómo dividir una cadena en un delimitador han dado lugar a algunas funciones útiles para la división de cadenas cuando se conoce la secuencia (es decir, véase más adelante):SQL 2005 Dividir por comas Columna Separado En el delimitador

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 

esto funciona bien para una cadena conocido como:

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

Sin embargo, me gustaría pasar una columna a una función, y lo han unioned junto con mis otros datos en su propia fila ... por ejemplo, dados los datos :

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

me gustaría escribir algo como:

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

y volver

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

Es esto posible, o alguien ha hecho esto antes?

+1

99% de las veces o más columnas separadas por comas son el resultado de una mala desi gn en primer lugar. El único lugar para una función dividida en el nivel del servidor es refactorizar esas columnas en su propia tabla. –

+0

Espero que esta tabla sea de su base de datos provisional y contenga datos brutos de un sistema propietario donde no tiene forma de cambiar el diseño de la tabla. – VVS

Respuesta

13

Sí, es posible con 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 

Notas:

  1. Usted debe agregar un índice para el conjunto de resultados de la columna de separación, de manera que devuelve dos columnas, IndexNumber y Value.

  2. Las implementaciones en línea con una tabla de números son generalmente más rápidas que su versión de procedimiento aquí.

por ejemplo:

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 tiene la página definitiva sobre esto, pienso: http://www.sommarskog.se/arrays-in-sql-2005.html

+0

Excelente Peter.Me salvó un ** de muchos problemas :) –

10

Solucione el problema de la forma correcta: convierta esa columna en una tabla relacionada. Nada bueno viene de las columnas escalares separadas por comas.

+0

Lamentablemente no es mi situación ideal, pero aún así es correcta. –

0

Usted podría intentar algo como:

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

Eso podría funcionar ... Creo. – VVS

+0

Ugh, mala sintaxis de unión también. –

+0

Intenté esto, que lamentablemente no funcionó ... gracias por su intento. –

1

+1 a los comentarios anti-CSV, pero si debe hacerlo usted utilizaría CRUZ aplicar o 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 

Uso:

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