Split Lista SQL Server

Split de Lista no SQL Server

Noutro dia precisei separar uma lista de valores separados por vírgula em um procedimento do SQL Server 2019. Essa lista de valores era passada via parâmetro da Stored Procedure.

Como não encontrei um tipo de dados adequado no SQL Server, então resolvi implementar uma função que retornasse uma lista com separador opcional.

Quem sabe um dia a Microsoft não implemente algo, como já existe no PostgreSQL, e pelo que me lembro, desde sua versão 7.1. [0]

A partir do SQL Server 2005 podemos utilizar o XML, por exemplo, contudo não vi a necessidade de sobrecarga se poderia utilizar algo mais simples e eficiente. Essa solução serve para vários tipos de estruturas e pode ser útil para relatórios mais complexos.

A função de Split da lista do SQL Server ficou bem para a minha necessidade. Talvez tu possas ter uma variação ou melhoria no código. Segue o caso de teste:

Parâmetro de Entrada:

lista (1,2,3,4,5,6,7)

Retorno esperado:

lista
1
2
3
4
5
6
7

Para isso vou passar a lista como uma variável do tipo varchar e vou incluir um separador ',' (vírgula).

O retorno será em uma @listaTabela, do tipo table.

  create function dbo.fg_split (@lista varchar(max), @separador varchar(max) = ',')

  returns @listaTabela table (lista varchar(max))

  -- Return Table [1]

  -- @listaTabela = Variável do tipo table que receberá o resultado

  as begin

     -- Variáveis que serão utilizadas

     -- @posicao = Posição do separador na lista

     -- @anterior = Posição inicial para percorrer a lista

     declare @posicao int, @anterior int

  

     set @lista = @lista + @separador

     set @anterior = 1

     set @posicao = charindex(@separador, @lista)

     -- charindex [2]

  

     while @posicao > 0

     begin

      if @posicao - @anterior > 0

       insert into @listaTabela values (substring(@lista, @anterior, @posicao - @anterior))

  

      if @posicao >= len(@lista) break

       set @anterior = @posicao + 1

  

      set @posicao = charindex(@separador, @lista, @anterior)

     end

     return

  end

  GO

  

  select * from dbo.fg_split('1,2,3,4,5,6,7',',')

  GO

 

Por quê utilizar esta técnica? Performance!

 

Aqui é feita uma chamada para o banco de dados.

 

Para os “puristas” do design pattern, pergunto: Por quê não seria uma boa ideia passar uma coleção para um procedimento armazenado? Se for uma solução ruim, então, é uma má ideia no .NET passar uma coleção como argumento para um método!

 

 

 

[0] https://www.postgresql.org/docs/12/arrays.html

[1] https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/sql/linq/how-to-use-table-valued-user-defined-functions

[2] https://docs.microsoft.com/en-us/sql/t-sql/functions/charindex-transact-sql?f1url=https%3A%2F%2Fmsdn.microsoft.com%2Fquery%2Fdev15.query%3FappId%3DDev15IDEF1%26l%3DEN-US%26k%3Dk(charindex_TSQL);k(sql13.swb.tsqlresults.f1);k(sql13.swb.tsqlquery.f1);k(MiscellaneousFilesProject);k(DevLang-TSQL)%26rd%3Dtrue&view=sql-server-ver15

Anderson Abreu