Extrair valores de uma string segundo um padrão com SQL de maneira simples

 

Há uns dias necessitei de retirar alguns valores de configuração a partir de uma tabela, onde estavam codificadas com este estilo

'( [B2] = 1 ) and ( [B32] = 1 ) and ( [A38] = 1 )'

Neste caso, precisava de encontrar o “número da A”, neste caso 38.

Como sou preguiçoso e sei que daqui a uns dias iria precisar de saber também os “números da B” resolvi criar uma função que me resolvesse o problema e nunca mais tivesse de pensar no caso.

Como também gosto muito de DRY procurei nos locais habituais por soluções que se adaptassem ao meu caso.
Encontrei várias soluções interessantes, entre elas algumas com recurso a CTE’s recursivas (trocadilho intencional…) mas nenhuma resolvia o meu caso concreto.

A questão está bem resolvida quando queremos encontrar as posições do padrão na string, ou de retirar o padrão da string, mas o que necessitava era de retirar o que estava depois do ‘[A’ até ao ‘]’.

 

Resolvi partilhar o meu SQL apenas para alguém que tenha um problema similar possa pegar nisto e adaptar como entender.

Para resolver a minha situação, primeiro pensei em usar PATINDEX porque, em primeira análise, procurava um “padrão”, mas a CHARINDEX ajuda-me mais nesta situação, primeiro porque posso procurar por ‘[A’ , ‘[B’ e por ‘]’ directamente (sem ter questões com o ‘[‘ que faz parte dos caracteres que são tratados pelo LIKE como numa REGEX) e, segundo, neste caso a razão mais importante, posso usar o opcional terceiro parâmetro para procurar apenas a partir de certa posição (inexistente no PATINDEX). O código ficou muito mais simples.

 

Sei sempre que a minha string será pequena e que é uma função que vai ser chamada muito poucas vezes, tipicamente uma vez por dia, e por isso não me alonguei com questões de performance.

Fica o código de uma função similar à que acabei por implementar.

USE [TEST_DATABASE]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE function [dbo].[ExtractPatternFromString]
(
@SomeString varchar(max)
, @SearchType char(1)
)
returns @Dependencies table (Dependency int)
with schemabinding
as
begin

declare @Separator varchar(10) = ']'
declare @Pattern varchar(10)
declare @index0 int = 0
declare @index1 int = 0
declare @index2 int = 1

if @SearchType = 'A'
  begin
    set @Pattern = '[A'
  end
else
  begin
    set @Pattern = '[B'
  end

while ( @index2 > 0)
  begin

    select @index1 = charindex(@Pattern, @SomeString, @index0) --apanhar o primeiro sítio onde está o [A
    if @index1 = 0 break; --se não existir, saltar logo do ciclo

    select @index2 = charindex(@Separador, @SomeString, @index1 )

    set @index0 = @index2

    insert into @Dependencies
      select substring(@SomeString, @index1 +2, @index2 -@index1 -2)
  end

return
end
GO

 

Para a usar basta

select Dependency from ExtractPatternFromString ( '( [B2] = 1 ) and ( [B32] = 1 ) and ( [A38] = 1 )', 'A')

Espero que possa dar alguma ajuda para resolver casos similares.

Leave a Reply

Your email address will not be published. Required fields are marked *