none
Armazenar vetor no banco RRS feed

  • Pergunta

  • Já sei que SQL Server não tem uma coluna do tipo vetor. Nesse caso como eu faço para gravar um vetor de inteiros no banco?

    Na aplicação eu tenho o modelo [Pessoa] com os campos, [nome], [telefone], [email], [tipo]. A coluna [tipo] deve ser uma matriz de inteiros de 1 a 3, representando os papeis que essa pessoa assume (1 = Client, 2 = Funcionario, 3 = Dependente).
    Uma pessoa pode ser tanto um funcionário como um cliente, nesse caso, na aplicação, a propriedade tipo é uma matriz de inteiro {1, 2}, que representa que esse cliente é tanto um cliente como um funcionário. Se a pessoa for tanto um funcionário quanto um dependente então a matriz seria {1, 3}.
    Obviamente existe uma tabela no banco chamada [pessoa] com colunas representando as propriedades da classe Pessoa na aplicação. Que tipo de coluna eu uso no SQL Server para representar a propriedade [tipo], que na classe é representada por um vetor?

    Eu penssei em criar uma tabela só para armazenar os tipos de uma pessoa. Mas honestamente não gosto da ideia, já que no PostgreSQL bastava que eu criasse uma coluna do tipo INTEGER[]. Bingo! estava solucionado o problema.
    quinta-feira, 7 de julho de 2016 18:36

Respostas

  • Matheus,

    Realmente array SQL Server não existe, você pode fazer algumas implementações utilizando tabelas temporários ou até mesmo uma estrutura em XML.

    Veja se estes exemplos podem te ajudar:

    DECLARE @StringDaAplicacao VARCHAR(1000)
    
    SET @StringDaAplicacao = '"jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"'
    
     
    
    DECLARE @xml XML, @Var VARCHAR(1000)
    
     
    
    -- Retirar as aspas duplas e espaços
    
    SET @Var = REPLACE(@StringDaAplicacao,'"','')
    
    SET @Var = REPLACE(@Var,' ','')
    
     
    
    -- Substituir o separador por uma tag
    
    SET @Var = REPLACE(@Var,',','</i><i>')
    
     
    
    -- Colocar as tags iniciais
    
    SET @Var = '<e><i>' + @Var + '</i></e>'
    
     
    
    -- Converte para XML
    
    SET @xml = CAST(@Var AS XML)
    
     
    
    -- Retorna os valores em formato tabular
    
    SELECT t.c.value('.','char(3)') 
    
    FROM @xml.nodes('/e/i') T(c)
    

    Set NoCount On;
    
    Use tempdb;
    
    If OBJECT_ID('dbo.Numeracao','U') Is Not Null
     Drop Table dbo.Numeracao;
    
    Create Table dbo.Numeracao
    (Numero Int Not Null Primary Key) ;
    Go
    
    Declare @ValorMaximo Int, 
                    @Contador Int;
                    
    Set @ValorMaximo=1000000;
    Set @Contador=1;
    
    Insert Into dbo.Numeracao Values(1)    
    
    While @Contador * 2 <= @ValorMaximo
     Begin
     
      Insert Into dbo.Numeracao
       Select Numero+@Contador from dbo.Numeracao;
        
      Set @Contador *= 2;        
     End 
    
    Insert Into dbo.Numeracao
     Select Numero + @Contador from dbo.Numeracao
     Where Numero + @Contador <= @ValorMaximo
    Go
    
    IF OBJECT_ID('dbo.Arrays') Is Not Null
     Drop Table dbo.Arrays;
    
    Create Table dbo.Arrays
    (Idx Varchar(10) Not Null Primary Key,
      Elementos Varchar(8000) Not Null)
    Go
    
    Insert Into Arrays(Idx, Elementos) 
    Values 
     ('A','20,223,2544,25567,14'),
     ('B','30,-23433,28'),
     ('C','12,10,8099,12,1200,13,12,14,10,9'),
     ('D','-4,-6,-45678,-2') 
    
    Select A.Idx, A.Elementos, 
                N.Numero
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos)
                                      And SUBSTRING (Elementos, Numero, 1) = ','                        
                                      
    Select A.Idx, 
               Substring(A.Elementos, N.Numero,  
                CHARINDEX(',', A.Elementos + ',', N.Numero)-N.Numero) As Elementos            
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos) + 1
                                      And SUBSTRING (',' + A.Elementos, Numero, 1) = ','
                                      
     Select ROW_NUMBER() Over(Partition By A.Idx Order By N.Numero) As Posição,
               A.Idx, 
              Substring(A.Elementos, N.Numero, CHARINDEX(',', A.Elementos +',', N.Numero)-N.Numero) As Elementos            
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos) 
                                      And SUBSTRING (','+A.Elementos, Numero, 1) = ','                                 
    
    With Split As
    (
     Select Idx, 1 As Pos, 1 As PosIni,
                CharIndex(',',Elementos + ',')  - 1 As PosFim
     From dbo.Arrays
     Where DATALENGTH(Elementos) > 0
    
     Union All
    
     Select Spl.Idx, Spl.Pos+1, Spl.PosFim + 2,
                CHARINDEX(',', A.Elementos + ',', Spl.PosFim + 2) - 1
     From Split As Spl Inner Join dbo.Arrays A
                                  On A.Idx = Spl.Idx
                                  And CHARINDEX(',', A.Elementos + ',', Spl.PosFim + 2) > 0
    )
    Select A.Idx, Spl.Pos,
               CAST(SUBSTRING(A.Elementos, Spl.PosIni, Spl.PosFim-Spl.PosIni+1) As Int) As Elementos
    From dbo.Arrays A Join Split As Spl
                                    On spl.Idx = A.Idx
    Order By A.Idx, Spl.Pos; 
    
    -- Construindo a Estrutura Completa do Array --
    Create Table dbo.ArrayCompleto
    (Idx Int Identity Primary Key,
     Identificador Char(1) Not Null,
     Elementos Varchar(10))
    
    -- Inserindo os dados na Tabela ArrayCompleto --   
    Insert Into ArrayCompleto (Identificador, Elementos)
    Select A.Idx, 
               Substring(A.Elementos, N.Numero,  
                CHARINDEX(',', A.Elementos + ',', N.Numero)-N.Numero) As Elementos
    
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos) + 1
                                      And SUBSTRING (',' + A.Elementos, Numero, 1) = ','
    
    Select * from ArrayCompleto

    -- 1. crie um table type para ser seu array --
    
    Create type MeuArray as table(valor nvarchar(200))
    go
    
    -- 2. crie a função que irá fazer a procura do valor no "array" --
    
    Create function TestaExistencia (@valor nvarchar(200), @array MeuArray readonly)
    returns bit
    as
    begin
      declare @achou as  bit = 0
      if exists (select 1 from @array where @valor in (select valor from @array))
      begin
         set @achou = 1
      end
      return @achou
    end
    go
    
    -- 3. Utilizando --
    
    declare @acheIsso nvarchar(200) = 'Oi'
    declare @listaDeValores MeuArray
    
    --Insert into @listaDeValores values ('Oi'),( 'Tchau'),( 'Good Bye'),( 'Hello World!'),( 'Vaza!'),( 'Da linha'),( 'Some')
    
    Select dbo.TestaExistencia(@acheIsso, @listaDeValores)
    
    


    Pedro Antonio Galvao Junior [MVP | MCC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | Professor Universitario | SoroCodigos | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    • Marcado como Resposta Thales F Quintas segunda-feira, 11 de julho de 2016 15:24
    quinta-feira, 7 de julho de 2016 18:43
  • Deleted
    • Marcado como Resposta Thales F Quintas segunda-feira, 11 de julho de 2016 15:24
    quinta-feira, 7 de julho de 2016 19:00

Todas as Respostas

  • Matheus,

    Realmente array SQL Server não existe, você pode fazer algumas implementações utilizando tabelas temporários ou até mesmo uma estrutura em XML.

    Veja se estes exemplos podem te ajudar:

    DECLARE @StringDaAplicacao VARCHAR(1000)
    
    SET @StringDaAplicacao = '"jan", "fev", "mar", "abr", "mai", "jun", "jul", "ago", "set", "out", "nov", "dez"'
    
     
    
    DECLARE @xml XML, @Var VARCHAR(1000)
    
     
    
    -- Retirar as aspas duplas e espaços
    
    SET @Var = REPLACE(@StringDaAplicacao,'"','')
    
    SET @Var = REPLACE(@Var,' ','')
    
     
    
    -- Substituir o separador por uma tag
    
    SET @Var = REPLACE(@Var,',','</i><i>')
    
     
    
    -- Colocar as tags iniciais
    
    SET @Var = '<e><i>' + @Var + '</i></e>'
    
     
    
    -- Converte para XML
    
    SET @xml = CAST(@Var AS XML)
    
     
    
    -- Retorna os valores em formato tabular
    
    SELECT t.c.value('.','char(3)') 
    
    FROM @xml.nodes('/e/i') T(c)
    

    Set NoCount On;
    
    Use tempdb;
    
    If OBJECT_ID('dbo.Numeracao','U') Is Not Null
     Drop Table dbo.Numeracao;
    
    Create Table dbo.Numeracao
    (Numero Int Not Null Primary Key) ;
    Go
    
    Declare @ValorMaximo Int, 
                    @Contador Int;
                    
    Set @ValorMaximo=1000000;
    Set @Contador=1;
    
    Insert Into dbo.Numeracao Values(1)    
    
    While @Contador * 2 <= @ValorMaximo
     Begin
     
      Insert Into dbo.Numeracao
       Select Numero+@Contador from dbo.Numeracao;
        
      Set @Contador *= 2;        
     End 
    
    Insert Into dbo.Numeracao
     Select Numero + @Contador from dbo.Numeracao
     Where Numero + @Contador <= @ValorMaximo
    Go
    
    IF OBJECT_ID('dbo.Arrays') Is Not Null
     Drop Table dbo.Arrays;
    
    Create Table dbo.Arrays
    (Idx Varchar(10) Not Null Primary Key,
      Elementos Varchar(8000) Not Null)
    Go
    
    Insert Into Arrays(Idx, Elementos) 
    Values 
     ('A','20,223,2544,25567,14'),
     ('B','30,-23433,28'),
     ('C','12,10,8099,12,1200,13,12,14,10,9'),
     ('D','-4,-6,-45678,-2') 
    
    Select A.Idx, A.Elementos, 
                N.Numero
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos)
                                      And SUBSTRING (Elementos, Numero, 1) = ','                        
                                      
    Select A.Idx, 
               Substring(A.Elementos, N.Numero,  
                CHARINDEX(',', A.Elementos + ',', N.Numero)-N.Numero) As Elementos            
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos) + 1
                                      And SUBSTRING (',' + A.Elementos, Numero, 1) = ','
                                      
     Select ROW_NUMBER() Over(Partition By A.Idx Order By N.Numero) As Posição,
               A.Idx, 
              Substring(A.Elementos, N.Numero, CHARINDEX(',', A.Elementos +',', N.Numero)-N.Numero) As Elementos            
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos) 
                                      And SUBSTRING (','+A.Elementos, Numero, 1) = ','                                 
    
    With Split As
    (
     Select Idx, 1 As Pos, 1 As PosIni,
                CharIndex(',',Elementos + ',')  - 1 As PosFim
     From dbo.Arrays
     Where DATALENGTH(Elementos) > 0
    
     Union All
    
     Select Spl.Idx, Spl.Pos+1, Spl.PosFim + 2,
                CHARINDEX(',', A.Elementos + ',', Spl.PosFim + 2) - 1
     From Split As Spl Inner Join dbo.Arrays A
                                  On A.Idx = Spl.Idx
                                  And CHARINDEX(',', A.Elementos + ',', Spl.PosFim + 2) > 0
    )
    Select A.Idx, Spl.Pos,
               CAST(SUBSTRING(A.Elementos, Spl.PosIni, Spl.PosFim-Spl.PosIni+1) As Int) As Elementos
    From dbo.Arrays A Join Split As Spl
                                    On spl.Idx = A.Idx
    Order By A.Idx, Spl.Pos; 
    
    -- Construindo a Estrutura Completa do Array --
    Create Table dbo.ArrayCompleto
    (Idx Int Identity Primary Key,
     Identificador Char(1) Not Null,
     Elementos Varchar(10))
    
    -- Inserindo os dados na Tabela ArrayCompleto --   
    Insert Into ArrayCompleto (Identificador, Elementos)
    Select A.Idx, 
               Substring(A.Elementos, N.Numero,  
                CHARINDEX(',', A.Elementos + ',', N.Numero)-N.Numero) As Elementos
    
    from dbo.Arrays A Join dbo.Numeracao N
                                      On N.Numero <= DATALENGTH(A.Elementos) + 1
                                      And SUBSTRING (',' + A.Elementos, Numero, 1) = ','
    
    Select * from ArrayCompleto

    -- 1. crie um table type para ser seu array --
    
    Create type MeuArray as table(valor nvarchar(200))
    go
    
    -- 2. crie a função que irá fazer a procura do valor no "array" --
    
    Create function TestaExistencia (@valor nvarchar(200), @array MeuArray readonly)
    returns bit
    as
    begin
      declare @achou as  bit = 0
      if exists (select 1 from @array where @valor in (select valor from @array))
      begin
         set @achou = 1
      end
      return @achou
    end
    go
    
    -- 3. Utilizando --
    
    declare @acheIsso nvarchar(200) = 'Oi'
    declare @listaDeValores MeuArray
    
    --Insert into @listaDeValores values ('Oi'),( 'Tchau'),( 'Good Bye'),( 'Hello World!'),( 'Vaza!'),( 'Da linha'),( 'Some')
    
    Select dbo.TestaExistencia(@acheIsso, @listaDeValores)
    
    


    Pedro Antonio Galvao Junior [MVP | MCC | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | Professor Universitario | SoroCodigos | @JuniorGalvaoMVP | http://pedrogalvaojunior.wordpress.com]

    • Marcado como Resposta Thales F Quintas segunda-feira, 11 de julho de 2016 15:24
    quinta-feira, 7 de julho de 2016 18:43
  • Deleted
    • Marcado como Resposta Thales F Quintas segunda-feira, 11 de julho de 2016 15:24
    quinta-feira, 7 de julho de 2016 19:00
  • Oi Matheus.

    Pensando numa modelagem relacional, eu criaria uma segunda tabela para relacionar Pessoas com Tipo.

    Mas você citou que não está gostando muito dessa ideia!

    Outra opção seria criar três colunas "Cliente", "Funcionario" e "Dependente " (boolean ou bit, por exemplo).

    Lembrando que essa segunda alternativa só seria interessante caso os tipos se restrinjam a somente essas três opções!

    Também existem outras alternativas, reflita e veja qual te atende melhor.

    quinta-feira, 7 de julho de 2016 19:04
  • Matheus,

    Desenvolvendo o sistema de gerenciamento e cálculo de Participação nos resultados do grupo no qual trabalho, tive uma situação parecida.

    Tinha que dizer em quais ciclos o indicador estava ativo ou não. Poderia ter criado uma tabela fazendo o relacionamento do indicador com o ciclo, mas optei por criar um campo que concatena as informações de ciclo em um campo chamado "ciclos":

    Ex: 132.145.149

    Como o ciclo é semestral, terei poucos ciclos e o número de indicadores também não é tão grande assim, então essa estratégia me atendeu muito bem sem a necessidade de uma nova tabela de relacionamento.

    Vale a pena verificar se a sugestão do Rafael Jucá não te atende, no caso de ser apenas essas três opções.

    Att,


    Antero Marques

    _______________________________________________________________________________

    Se a resposta for útil, marque como útil, se respondeu totalmente sua dúvida, marque como resposta. O Fórum MSDN é utilizado também como base de conhecimento, então é responsabilidade de todos mantê-lo organizado e funcional.


    sexta-feira, 8 de julho de 2016 15:56
  • Bom dia,

    Por falta de retorno, esta thread será encerrada.

    Caso seja necessário, por gentileza, abra uma nova thread.

    Atenciosamente


    Thales F Quintas

    Esse conteúdo é fornecido sem garantias de qualquer tipo, seja expressa ou implícita

    TechNet Community Support

    Por favor, lembre-se de Marcar como Resposta as postagens que resolveram o seu problema. Essa é uma maneira comum de reconhecer aqueles que o ajudaram e fazer com que seja mais fácil para os outros visitantes encontrarem a resolução mais tarde.

    segunda-feira, 11 de julho de 2016 15:24