none
Transformar uma String em código. RRS feed

  • Pergunta

  • O que quero fazer é o seguinte:

    eu tenho um parâmentro chamado @valorX do tipo VARCHAR(MAX), aonde é atribuido algo do tipo : '1;2;3;4;5;6;7;8;9'

    Eu queria que minha procedure fizesse o seguinte :

    Pegar esse parâmetro @valorX e desmembralo, comparando a variável x  com cada valor entre ";" do parâmetro, ficando assim:

    Where
    x = '1' OR x = '2' OR x='3' OR x='4' OR x='5' OR x='6' OR x='7' OR x='8' OR x='9'


    Tem como fazer isso?


    sexta-feira, 4 de janeiro de 2008 13:24

Respostas

  • Bom Dia,

     

    Não sei se entendi bem, mas talvez o código abaixo o atenda:

     

    Code Block

    DECLARE @strSQL VARCHAR(1000), @par VARCHAR(300)

    SET @par = '1;2;3;4;5;6;7;8;9'

    SET @strSQL = 'SELECT Alguma Coisa FROM Tabela'

    SET @strSQL = @strSQL + ' WHERE '

    SET @par = REPLACE(@par,';',''' Or Campo = ''')

    SET @par = LEFT(@par,LEN(@par)-9)

    SET @par = 'Campo = ''' + @par

    SET @strSQL = @strSQL + @par

    --PRINT @strSQL

    EXEC(@strSQL)

     

     

     

    [ ]s,

     

    Gustavo

    sexta-feira, 4 de janeiro de 2008 13:39
  • Bom dia,

     

    Não pode usar o IN??

     

    DECLARE @valorX VARCHAR(max)

    SET @valorX = '1;2;3;4;5;6;7;8;9'

     

    set @valorX = replace(@valorX ,';',',')

     

    SELECT @valorX

     

    where IN(@valorX)

     

    Espero ter ajudado,

     

    Abraço,

     

    chapolin.rio@gmail.com

    sexta-feira, 4 de janeiro de 2008 13:39
  •  

    Renan,

     

    Veja esta função que criei a algum tempo, já postei ela algumas vezes, vai resolver seu problema:

     

    Code Block

    CREATE FUNCTION [dbo].[fnStringToInt] (@String VARCHAR(1000), @Separador CHAR(1))

    RETURNS @Inteiros TABLE (IDs int)

    AS

    BEGIN

    DECLARE @Int INT

    IF PATINDEX ('%' + @Separador + '%', @String) = 0

    INSERT INTO @Inteiros VALUES (@String)

    ELSE

    BEGIN

    WHILE PATINDEX ('%' + @Separador + '%', @String) > 0

    BEGIN

    INSERT INTO @Inteiros VALUES (CONVERT (INT, SUBSTRING (@String, 1, PATINDEX ('%' + @Separador + '%', @String) - 1)))

    SET @String = SUBSTRING (@String, PATINDEX ('%' + @Separador + '%', @String) + 1, LEN(@String))

    END

    INSERT INTO @Inteiros VALUES (@String)

    END

    RETURN

    END

     

     

     

    Para usar ela, faça da seguinte maneira:

     

    Code Block

    SELECT Campos

    FROM SuaTabela

    WHERE Campo IN (SELECT IDs FROM [dbo].[fnStringToInt] ('1;2;3;4;5;6', ';'))

     

     

     

    Ou pode até mesmo fazer um JOIN com o resultado da function.

     

     

    Se tiver problemas, retorne.

     

     

    Abraço

    segunda-feira, 7 de janeiro de 2008 15:49
  • Claro, sem problemas, Wink

     

    O problema está sendo causado pela diferença no COLLATE, recomendo verificar o collate do campo que está sendo comparado para então fazer a mudança da função.

     

    Por exemplo, se na coluna estiver sendo usado o collate "SQL_Latin1_General_CP1_CI_AI", faça assim:

     

     

    Code Block

    CREATE FUNCTION [dbo].[fnStringToRef] (@String VARCHAR(1000), @Separador CHAR(1))

    RETURNS @Valores TABLE (@Val VARCHAR (7) COLLATE SQL_Latin1_General_CP1_CI_AI)

    AS

    BEGIN

    .

    .

    .

     

     

     

     

    Ou, em último caso, faça assim:

     

    Code Block

    SELECT *

    FROM Atendimento

    WHERE

    ateSaida COLLATE SQL_Latin1_General_CP1_CI_AI IN(SELECT IDs COLLATE SQL_Latin1_General_CP1_CI_AI FROM [dbo].[fnStringToRef] ('10/2005;05/2006', ';'))

     

     

     

     

    Mas, pessoalmente, prefiro a primeira opção por questões de desempenho.

     

     

    Abraço!!

    segunda-feira, 7 de janeiro de 2008 16:34

Todas as Respostas

  • Bom Dia,

     

    Não sei se entendi bem, mas talvez o código abaixo o atenda:

     

    Code Block

    DECLARE @strSQL VARCHAR(1000), @par VARCHAR(300)

    SET @par = '1;2;3;4;5;6;7;8;9'

    SET @strSQL = 'SELECT Alguma Coisa FROM Tabela'

    SET @strSQL = @strSQL + ' WHERE '

    SET @par = REPLACE(@par,';',''' Or Campo = ''')

    SET @par = LEFT(@par,LEN(@par)-9)

    SET @par = 'Campo = ''' + @par

    SET @strSQL = @strSQL + @par

    --PRINT @strSQL

    EXEC(@strSQL)

     

     

     

    [ ]s,

     

    Gustavo

    sexta-feira, 4 de janeiro de 2008 13:39
  • Bom dia,

     

    Não pode usar o IN??

     

    DECLARE @valorX VARCHAR(max)

    SET @valorX = '1;2;3;4;5;6;7;8;9'

     

    set @valorX = replace(@valorX ,';',',')

     

    SELECT @valorX

     

    where IN(@valorX)

     

    Espero ter ajudado,

     

    Abraço,

     

    chapolin.rio@gmail.com

    sexta-feira, 4 de janeiro de 2008 13:39
  • *@#&*!& BIXO!!!! TU ME AJUDO PRA !@#(*#@!)(*@# !!!!!!!!!!

    Da vontade até de gritar aqui, vc me respondeu duas coisa, a primeira era sobre o desmembramento de string (sinto lhe informar que não é mais necessario graças a vc, ehehehehe)

    Só pra vc ter uma idéia, eu tava criando vários parâmetros para serem passados para dentro da where da minha procedure...

    Porém tudo oq eu precisava era que eu pudesse montar minha where via código e que pudesse passar toda ela via parâmetro na minha procedure, eu não sabia como transformar uma string em codigo, ou fazer ela ser executada.

    Po bixo, tu me salvo mesmo.

    Resumindo.... VLW CHAPOLA E GUSTAVO!!!
    sexta-feira, 4 de janeiro de 2008 13:58
  • Opa!!!!!!!!!!!!

     

    Bom ter resolvido!!!! Obrigado pelo retorno.

     

    Quando precisar, estamos aí.

     

    Abraço,

     

    chapolin.rio@gmail.com

    sexta-feira, 4 de janeiro de 2008 14:08
  • Vlw chapola, mas olha só, não está dando certo sua query (pelo menos eu não consegui rodar), da erro... ao meu ver é pq fica mais ou menos assim:


    DECLARE @valorX VARCHAR(max)

    SET @valorX = '1;2;3;4;5;6;7;8;9'

     

    set @valorX = replace(@valorX ,';',',')

     

    SELECT * FROM [TABELA] vWHERE alor IN('1,2,3,4,5,6,7')


    Ele vai ler 1,2,3,4,5,6,7 como se fosse uma variável. não?


    sexta-feira, 4 de janeiro de 2008 15:57
  • cara,

     

    Tira os Plic's o IN Plics = '  deixa ele dessa forma IN(1,2,3,4,5,6,7) e veja se funciona.

     

    Abraço

    sexta-feira, 4 de janeiro de 2008 16:01
  • Boa Tarde,

     

    Que bom que conseguimos ajudar com o seu problema. É sempre gratificante ver uma solução nossa funcionando.

     

    [ ]s,

     

    Gustavo

     

    sexta-feira, 4 de janeiro de 2008 16:03
  • cara,

     

    Tira os Plic's o IN Plics = '  deixa ele dessa forma IN(1,2,3,4,5,6,7) e veja se funciona.



    Esse é o problema, não consigo fazer isso.

    Olha oq está acontecendo:

    A procedure ficou assim :

    DECLARE
    @valorX VARCHAR(max)

    SET @valorX = '40;148'
    SET @valorX = replace(@valorX ,';',',')

    SELECT conContrato FROM Contratos
    WHERE conContrato IN(@valorX)


    Quando executo da o erro :

    Msg 245, Level 16, State 1, Line 6
    Conversion failed when converting the varchar value '40,148' to data type int.
    segunda-feira, 7 de janeiro de 2008 15:26
  • Boa Tarde,

     

    Infelizmente a solução abaixo não irá funcionar:

     

    DECLARE @valorX VARCHAR(max)

    SET @valorX = '1;2;3;4;5;6;7;8;9'

     

    set @valorX = replace(@valorX ,';',',')

     

    SELECT * FROM [TABELA] WHERE valor IN('1,2,3,4,5,6,7')

     

    Dessa forma ele procurará todos os registros cujo o valor é igual '1,2,3,4,5,6,7'. Essa condição não é semelhante a

     

    WHERE valor IN(1,2,3,4,5,6,7)

     

    Embora pareça ser uma pena, isso é necessário. Se alguém quisesse pesquisar o valor '1,2,3,4,5,6,7' e a consulta entendesse como um IN, não seria possível realizar essa busca. Esse raciocínio só irá funcionar, se você fizer uma construção dinâmica como a que eu havia sugerido.

     

    [ ]s,

     

    Gustavo

    segunda-feira, 7 de janeiro de 2008 15:30
  • Exatamente Gustavo....

    Porém não posso fazer uma construção dinâmica, pois estou usando report service e ele não consegue vincular procedures como a sua para algum relatório, pois ele não identifica os campos e etc...



    Eu pensei em algo do tipo :

    DECLARE @strSQL VARCHAR(1000), @par VARCHAR(300)

    SET @par = '40,148'
    SET @strSQL = 'SELECT conContrato FROM Gss_Contrato'
    SET @strSQL = @strSQL + ' WHERE conContrato IN (' + @par + ')'

    SELECT conContrato FROM (
    EXEC(@strSQL)
    )


    Assim ele identificaria os campos de retorno, podendo essa procedure ser vinculada a um relatório.
    segunda-feira, 7 de janeiro de 2008 15:38
  •  

    R3N4N

     

    Vc pode tirar os plic's de duas formas

     

    1º - SET @valorX = '40;148'

          SET @valorX = REPLACE(replace(@valorX ,';',','),'''','')

     

    SET @valorX = SUBSTRING(replace(@valorX ,';',','),1,LEN(@valorX)-1)

    segunda-feira, 7 de janeiro de 2008 15:46
  •  

    Renan,

     

    Veja esta função que criei a algum tempo, já postei ela algumas vezes, vai resolver seu problema:

     

    Code Block

    CREATE FUNCTION [dbo].[fnStringToInt] (@String VARCHAR(1000), @Separador CHAR(1))

    RETURNS @Inteiros TABLE (IDs int)

    AS

    BEGIN

    DECLARE @Int INT

    IF PATINDEX ('%' + @Separador + '%', @String) = 0

    INSERT INTO @Inteiros VALUES (@String)

    ELSE

    BEGIN

    WHILE PATINDEX ('%' + @Separador + '%', @String) > 0

    BEGIN

    INSERT INTO @Inteiros VALUES (CONVERT (INT, SUBSTRING (@String, 1, PATINDEX ('%' + @Separador + '%', @String) - 1)))

    SET @String = SUBSTRING (@String, PATINDEX ('%' + @Separador + '%', @String) + 1, LEN(@String))

    END

    INSERT INTO @Inteiros VALUES (@String)

    END

    RETURN

    END

     

     

     

    Para usar ela, faça da seguinte maneira:

     

    Code Block

    SELECT Campos

    FROM SuaTabela

    WHERE Campo IN (SELECT IDs FROM [dbo].[fnStringToInt] ('1;2;3;4;5;6', ';'))

     

     

     

    Ou pode até mesmo fazer um JOIN com o resultado da function.

     

     

    Se tiver problemas, retorne.

     

     

    Abraço

    segunda-feira, 7 de janeiro de 2008 15:49
  • KARAka veio, tu é foda mesmo, alias vcs são =D


    Pode me explicar uma coisinha so:

    PATINDEX é igual a IndexOf em C#, ou seja pega o index do caracter especificado?
    segunda-feira, 7 de janeiro de 2008 16:05
  •  

    É isso mesmo, é a mesma coisa.

     

     

    Abraço

    segunda-feira, 7 de janeiro de 2008 16:10
  • Se não fosse pedir muito, vc pode me ajudar com uma função que estou fazendo...

    ela é basicamente a sua, mas ao invéz de INT, ela retorna uma tabela de VARCHAR(7)

    Bom, eu ja testei ela, e funciono, mas quando tento usar ela assim:

        SELECT *
        FROM Atendimento
        WHERE
            ateSaida IN(SELECT IDs FROM [dbo].[fnStringToRef] ('10/2005;05/2006', ';'))

    Minha função apresenta o seguinte erro :

    Msg 468, Level 16, State 9, Line 19
    Cannot resolve the collation conflict between "SQL_Latin1_General_CP1_CI_AI" and "SQL_Latin1_General_CP850_CI_AI" in the equal to operation.


    Se eu coloco só :

    SELECT IDs FROM [dbo].[fnStringToRef] ('10/2005;05/2006', ';') 

    ele traz numa boa, sem erros e sem nada, por isso presumo que o erro não esteja na função, e sim na comparação, mas não sei como resolver esse confito de collation

    segunda-feira, 7 de janeiro de 2008 16:23
  • Claro, sem problemas, Wink

     

    O problema está sendo causado pela diferença no COLLATE, recomendo verificar o collate do campo que está sendo comparado para então fazer a mudança da função.

     

    Por exemplo, se na coluna estiver sendo usado o collate "SQL_Latin1_General_CP1_CI_AI", faça assim:

     

     

    Code Block

    CREATE FUNCTION [dbo].[fnStringToRef] (@String VARCHAR(1000), @Separador CHAR(1))

    RETURNS @Valores TABLE (@Val VARCHAR (7) COLLATE SQL_Latin1_General_CP1_CI_AI)

    AS

    BEGIN

    .

    .

    .

     

     

     

     

    Ou, em último caso, faça assim:

     

    Code Block

    SELECT *

    FROM Atendimento

    WHERE

    ateSaida COLLATE SQL_Latin1_General_CP1_CI_AI IN(SELECT IDs COLLATE SQL_Latin1_General_CP1_CI_AI FROM [dbo].[fnStringToRef] ('10/2005;05/2006', ';'))

     

     

     

     

    Mas, pessoalmente, prefiro a primeira opção por questões de desempenho.

     

     

    Abraço!!

    segunda-feira, 7 de janeiro de 2008 16:34
  • Cara,

    Uma vez tive problema com o Collation e resolvi usando o utilitário nesse link aqui:

     

    http://www.mcdbabrasil.com.br/modules.php?name=News&file=article&sid=244

     

    Ve se isso te ajuda.

     

    Abraço,

     

    chapolin.rio@gmail.com

    segunda-feira, 7 de janeiro de 2008 16:35
  •  

    Chapolin,

     

    É bom analisar bem a situação antes de sair trocando o COLLATE, ele deve estar ali por algum motivo. Fazendo a troca pode dar muitos problemas.

     

     

    Abraço

    segunda-feira, 7 de janeiro de 2008 16:41
  • Bom, vlw chapolin, mas não posso alterar o Collation...
    Mas vamos la, Alexandre, é o seguinte, vou postar meu procedimento:

    Code Block
    FUNCTION [dbo].[fnStringToRef] (@String VARCHAR(1000), @Separador CHAR(1))
    RETURNS @Referencias TABLE (IDs VARCHAR(7))
    AS
    BEGIN
        DECLARE @Ref VARCHAR(7)
        IF PATINDEX ('%' + @Separador + '%', @String) = 0
            INSERT INTO @Referencias VALUES (@String)
        ELSE BEGIN
            WHILE PATINDEX ('%' + @Separador + '%', @String) > 0 BEGIN
                INSERT INTO @Referencias VALUES (SUBSTRING (@String, 1, PATINDEX ('%' + @Separador + '%', @String) - 1))
                SET @String = SUBSTRING (@String, PATINDEX ('%' + @Separador + '%', @String) + 1, LEN(@String))
            END
            INSERT INTO @Referencias VALUES (@String)
        END
    RETURN
    END

    Usei da seguinte maneira :

    Code Block
        SELECT *
        FROM Gss_Atendimento
        WHERE
            ateReferencia IN(SELECT IDs FROM [dbo].[fnStringToRef] ('09/2006', ';'))

    Deu erro do collation, ai fiz a seguinte alteração :

    Code Block
        SELECT *
        FROM Gss_Atendimento
        WHERE
            ateReferencia IN(SELECT IDs COLLATE Latin1_General_CI_AI FROM [dbo].[fnStringToRef] ('09/2006', ';'))

    E deu certo, porém fiquei preocupado com oq vc falou sobre desempenho e alterei minha função para :

    Code Block
    ALTER FUNCTION [dbo].[fnStringToRef] (@String VARCHAR(1000), @Separador CHAR(1))
    RETURNS @Referencias TABLE (IDs VARCHAR(7) COLLATE Latin1_General_CI_AI)
    AS
    BEGIN
        DECLARE @Ref VARCHAR(7)
        IF PATINDEX ('%' + @Separador + '%', @String) = 0
            INSERT INTO @Referencias VALUES (@String)
        ELSE BEGIN
            WHILE PATINDEX ('%' + @Separador + '%', @String) > 0 BEGIN
                INSERT INTO @Referencias VALUES (SUBSTRING (@String, 1, PATINDEX ('%' + @Separador + '%', @String) - 1))
                SET @String = SUBSTRING (@String, PATINDEX ('%' + @Separador + '%', @String) + 1, LEN(@String))
            END
            INSERT INTO @Referencias VALUES (@String)
        END
    RETURN
    END

    e executei ela usando o comando :

    Code Block
        SELECT *
        FROM Gss_Atendimento
        WHERE
            ateReferencia IN(SELECT IDs FROM [dbo].[fnStringToRef] ('09/2006', ';'))

    Não deu certo...

    Oq vc aconselha, deixar no select mesmo ou insisti na idéia de colocar na função?
    segunda-feira, 7 de janeiro de 2008 16:58
  •  

    O Collate da coluna ateReferencia é "Latin1_General_CI_AI"??

     

    Deveria funcionar.

     

     

     

    Verifica com:

    sp_help Gss_Atendimento

     

     

    Abraço!!

    segunda-feira, 7 de janeiro de 2008 17:14
  • Nossa, vlw mesmo, to preso com esse negócio a mais de 1 semana, pesquisei pra kct e resolvi postar aqui.
    Chapolin,  Gustavo Maia Aguiar e Alexandre VM, vcs são 10 =D

    Alexandre, vlw cara, eu fiz oq vc falou, tava dando erro antes pq eu meio que chutei qual era a collation da coluna ateReferencia...

    Ai usei o comando q vc falou (sp_help Gss_Atendimento) e verifiquei certinho o collation, sendo ele o
    SQL_Latin1_General_CP850_CI_AI, portanto alterei minha função para tal collation e deu certo.

    ...

    Ufa, acabou, finalmente, finish, the end, not be continued!!!

    Vlw aew =D
    segunda-feira, 7 de janeiro de 2008 17:30
  •  

    Éééé... deixa esse negócio de chutar pro jogo de futebol, hehe. Aqui as coisas são binárias, ou é, ou não é, hehe.

     

     

    Abraço!!!

    segunda-feira, 7 de janeiro de 2008 17:42
  • Alexandre,

     

    É verdade. Aquele post é para alterar o collation do banco todo, uniformizando os collation's. Realmente não é uma prática recomendável para certos casos.

    Peço desculpas aí pela dica errada..Acontece!!!

     

    Abraço a todos,

     

    chapolin.rio@gmail.com

     

    segunda-feira, 7 de janeiro de 2008 18:23
  •  

    Chapolin,

     

    Sem problema, é bom saber que aquele recurso existe. Em algumas situações pode ser bem útil. Wink

     

     

    Abraço!!

    segunda-feira, 7 de janeiro de 2008 18:32