Como faço para dividir uma string para que eu possa acessar o item x?

votos
442

Usando o SQL Server, como faço para dividir uma string para que eu possa acessar o item x?

Dê uma string Olá John Smith. Como posso dividir a string pelo espaço e acessar o item no índice 1, que deve retornar John?

Publicado 05/08/2008 em 19:15
fonte usuário
Em outras línguas...                            


43 respostas

votos
335

Eu não acredito que o SQL Server tem uma função de divisão interna, de modo que não seja um UDF, a única resposta que eu sei é para seqüestrar a função ParseName:

SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 2) 

ParseName recebe uma string e divide-o no personagem período. É preciso um número como seu segundo argumento, e esse número especifica qual segmento da cadeia para voltar (trabalhando de trás para frente).

SELECT PARSENAME(REPLACE('Hello John Smith', ' ', '.'), 3)  --return Hello

problema óbvio é quando a corda já contém um período. Eu ainda acho que usando um UDF é a melhor maneira ... alguma outra sugestão?

Respondeu 05/08/2008 em 19:45
fonte usuário

votos
177

Você pode encontrar a solução no SQL definido pelo usuário função para analisar uma cadeia delimitada útil (de O Projeto de Código ).

Você pode usar essa lógica simples:

Declare @products varchar(200) = '1|20|3|343|44|6|8765'
Declare @individual varchar(20) = null

WHILE LEN(@products) > 0
BEGIN
    IF PATINDEX('%|%', @products) > 0
    BEGIN
        SET @individual = SUBSTRING(@products,
                                    0,
                                    PATINDEX('%|%', @products))
        SELECT @individual

        SET @products = SUBSTRING(@products,
                                  LEN(@individual + '|') + 1,
                                  LEN(@products))
    END
    ELSE
    BEGIN
        SET @individual = @products
        SET @products = NULL
        SELECT @individual
    END
END
Respondeu 05/08/2008 em 19:28
fonte usuário

votos
106

Em primeiro lugar, criar uma função (utilizando CTE, expressão tabela comum acaba com a necessidade de uma tabela de temperatura)

 create function dbo.SplitString 
    (
        @str nvarchar(4000), 
        @separator char(1)
    )
    returns table
    AS
    return (
        with tokens(p, a, b) AS (
            select 
                1, 
                1, 
                charindex(@separator, @str)
            union all
            select
                p + 1, 
                b + 1, 
                charindex(@separator, @str, b + 1)
            from tokens
            where b > 0
        )
        select
            p-1 zeroBasedOccurance,
            substring(
                @str, 
                a, 
                case when b > 0 then b-a ELSE 4000 end) 
            AS s
        from tokens
      )
    GO

Em seguida, usá-lo como qualquer tabela (ou modificá-lo para caber dentro de seu proc armazenado existente) como este.

select s 
from dbo.SplitString('Hello John Smith', ' ')
where zeroBasedOccurance=1

Atualizar

Versão anterior seria um fracasso para a cadeia de entrada mais de 4000 caracteres. Esta versão cuida da limitação:

create function dbo.SplitString 
(
    @str nvarchar(max), 
    @separator char(1)
)
returns table
AS
return (
with tokens(p, a, b) AS (
    select 
        cast(1 as bigint), 
        cast(1 as bigint), 
        charindex(@separator, @str)
    union all
    select
        p + 1, 
        b + 1, 
        charindex(@separator, @str, b + 1)
    from tokens
    where b > 0
)
select
    p-1 ItemIndex,
    substring(
        @str, 
        a, 
        case when b > 0 then b-a ELSE LEN(@str) end) 
    AS s
from tokens
);

GO

Uso permanece a mesma.

Respondeu 05/08/2008 em 19:57
fonte usuário

votos
51

A maioria das soluções aqui usar enquanto loops ou CTEs recursiva. A abordagem baseada em conjunto será superior, eu prometo:

CREATE FUNCTION [dbo].[SplitString]
    (
        @List NVARCHAR(MAX),
        @Delim VARCHAR(255)
    )
    RETURNS TABLE
    AS
        RETURN ( SELECT [Value] FROM 
          ( 
            SELECT 
              [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
              CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
            FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
              FROM sys.all_objects) AS x
              WHERE Number <= LEN(@List)
              AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim)) = @Delim
          ) AS y
        );

Mais informações sobre as funções rachadas, por isso (e prova de que), enquanto loops e CTEs recursiva não escala e melhores alternativas, se cordas divisão provenientes da camada de aplicação:

http://www.sqlperformance.com/2012/07/t-sql-queries/split-strings

http://www.sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql

http://sqlblog.com/blogs/aaron_bertrand/archive/2010/07/07/splitting-a-list-of-integers-another-roundup.aspx

Respondeu 12/11/2013 em 18:16
fonte usuário

votos
37

Você pode aproveitar uma tabela de números para fazer a análise de cadeia.

Criar um número tabela física:

    create table dbo.Numbers (N int primary key);
    insert into dbo.Numbers
        select top 1000 row_number() over(order by number) from master..spt_values
    go

Criar tabela de teste com 1000000 linhas

    create table #yak (i int identity(1,1) primary key, array varchar(50))

    insert into #yak(array)
        select 'a,b,c' from dbo.Numbers n cross join dbo.Numbers nn
    go

Criar a função

    create function [dbo].[ufn_ParseArray]
        (   @Input      nvarchar(4000), 
            @Delimiter  char(1) = ',',
            @BaseIdent  int
        )
    returns table as
    return  
        (   select  row_number() over (order by n asc) + (@BaseIdent - 1) [i],
                    substring(@Input, n, charindex(@Delimiter, @Input + @Delimiter, n) - n) s
            from    dbo.Numbers
            where   n <= convert(int, len(@Input)) and
                    substring(@Delimiter + @Input, n, 1) = @Delimiter
        )
    go

Usage (saídas 3mil linhas na década de 40 no meu laptop)

    select * 
    from #yak 
    cross apply dbo.ufn_ParseArray(array, ',', 1)

Limpar

    drop table dbo.Numbers;
    drop function  [dbo].[ufn_ParseArray]

Desempenho aqui não é incrível, mas chamar uma função sobre uma mesa de milhões de linhas não é a melhor ideia. Se estiver executando uma corda dividida em várias linhas Gostaria de evitar a função.

Respondeu 27/10/2008 em 17:48
fonte usuário

votos
20

Aqui é um UDF que irá fazê-lo. Ele irá retornar uma tabela com os valores delimitados, não tentei todos os cenários sobre isso, mas o seu exemplo funciona bem.


CREATE FUNCTION SplitString 
(
    -- Add the parameters for the function here
    @myString varchar(500),
    @deliminator varchar(10)
)
RETURNS 
@ReturnTable TABLE 
(
    -- Add the column definitions for the TABLE variable here
    [id] [int] IDENTITY(1,1) NOT NULL,
    [part] [varchar](50) NULL
)
AS
BEGIN
        Declare @iSpaces int
        Declare @part varchar(50)

        --initialize spaces
        Select @iSpaces = charindex(@deliminator,@myString,0)
        While @iSpaces > 0

        Begin
            Select @part = substring(@myString,0,charindex(@deliminator,@myString,0))

            Insert Into @ReturnTable(part)
            Select @part

    Select @myString = substring(@mystring,charindex(@deliminator,@myString,0)+ len(@deliminator),len(@myString) - charindex(' ',@myString,0))


            Select @iSpaces = charindex(@deliminator,@myString,0)
        end

        If len(@myString) > 0
            Insert Into @ReturnTable
            Select @myString

    RETURN 
END
GO

Você poderia chamá-lo assim:


Select * From SplitString('Hello John Smith',' ')

Edit: Atualizado solução para lidar com delimters com um len> 1 como em:


select * From SplitString('Hello**John**Smith','**')
Respondeu 05/08/2008 em 19:39
fonte usuário

votos
16

Nenhum código, mas leia o artigo definitivo sobre isso. Todas as soluções em outras respostas são sabores dos listados neste artigo: Matrizes e Listas em SQL Server 2005 and Beyond

Pessoalmente, eu usei uma solução tabela de números na maioria das vezes, porque ele combina com o que eu tenho que fazer ...

Respondeu 26/09/2010 em 14:44
fonte usuário

votos
15

Aqui eu postar uma maneira simples de solução

CREATE FUNCTION [dbo].[split](
          @delimited NVARCHAR(MAX),
          @delimiter NVARCHAR(100)
        ) RETURNS @t TABLE (id INT IDENTITY(1,1), val NVARCHAR(MAX))
        AS
        BEGIN
          DECLARE @xml XML
          SET @xml = N'<t>' + REPLACE(@delimited,@delimiter,'</t><t>') + '</t>'

          INSERT IGNORE  INTO @t(val)
          SELECT  r.value('.','varchar(MAX)') as item
          FROM  @xml.nodes('/t') as records(r)
          RETURN
        END


Executar a função como esta

  select * from dbo.split('Hello John Smith',' ')
Respondeu 30/01/2013 em 10:41
fonte usuário

votos
12

Esta questão é não se trata de uma abordagem dividida corda , mas sobre como obter o enésimo elemento .

Todas as respostas aqui estão fazendo algum tipo de divisão string usando recursão, CTEs, múltiplos CHARINDEX, REVERSEe PATINDEX, funções inventar, chamada para métodos CLR, tabelas de números, CROSS APPLYé ... A maioria das respostas cobrir muitas linhas de código.

Mas - se você realmente quer nada mais do que uma abordagem para obter o enésimo elemento - isso pode ser feito como verdadeiro one-liner , não UDF, nem mesmo um sub-select ... E, como um benefício extra: seguro tipo

Obter parte 2 delimitado por um espaço:

DECLARE @input NVARCHAR(100)=N'part1 part2 part3';
SELECT CAST(N'<x>' + REPLACE(@input,N' ',N'</x><x>') + N'</x>' AS XML).value('/x[2]','nvarchar(max)')

Claro que você pode usar variáveis para delimitador e posição (usar sql:columnpara recuperar a posição diretamente do valor de uma consulta):

DECLARE @dlmt NVARCHAR(10)=N' ';
DECLARE @pos INT = 2;
SELECT CAST(N'<x>' + REPLACE(@input,@dlmt,N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)')

Se a seqüência pode incluir caracteres proibidos (especialmente um entre &><), você ainda pode fazê-lo desta forma. Basta usar FOR XML PATHem sua string primeiro a substituir todos os caracteres proibidos com a sequência de escape montagem implicitamente.

É um caso muito especial se - além disso - o delimitador é o ponto e vírgula . Neste caso, eu substituir o delimitador primeiro a '# DLMT #', e substituir este com as tags XML, finalmente:

SET @input=N'Some <, > and &;Other äöü@€;One more';
SET @dlmt=N';';
SELECT CAST(N'<x>' + REPLACE((SELECT REPLACE(@input,@dlmt,'#DLMT#') AS [*] FOR XML PATH('')),N'#DLMT#',N'</x><x>') + N'</x>' AS XML).value('/x[sql:variable("@pos")][1]','nvarchar(max)');
Respondeu 08/07/2016 em 20:41
fonte usuário

votos
10

Que tal usar stringe values()afirmação?

DECLARE @str varchar(max)
SET @str = 'Hello John Smith'

DECLARE @separator varchar(max)
SET @separator = ' '

DECLARE @Splited TABLE(id int IDENTITY(1,1), item varchar(max))

SET @str = REPLACE(@str, @separator, '''),(''')
SET @str = 'SELECT * FROM (VALUES(''' + @str + ''')) AS V(A)' 

INSERT IGNORE  INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

O resultado conseguido-conjunto.

id  item
1   Hello
2   John
3   Smith
Respondeu 01/03/2013 em 17:26
fonte usuário

votos
10

Na minha opinião vocês estão fazendo isso muito complicado. Basta criar um UDF CLR e ser feito com ele.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Collections.Generic;

public partial class UserDefinedFunctions {
  [SqlFunction]
  public static SqlString SearchString(string Search) {
    List<string> SearchWords = new List<string>();
    foreach (string s in Search.Split(new char[] { ' ' })) {
      if (!s.ToLower().Equals("or") && !s.ToLower().Equals("and")) {
        SearchWords.Add(s);
      }
    }

    return new SqlString(string.Join(" OR ", SearchWords.ToArray()));
  }
};
Respondeu 19/07/2012 em 22:46
fonte usuário

votos
8

Esse padrão funciona bem e você pode generalizar

Convert(xml,'<n>'+Replace(FIELD,'.','</n><n>')+'</n>').value('(/n[INDEX])','TYPE')
                          ^^^^^                                   ^^^^^     ^^^^

nota CAMPO , INDEX e TYPE .

Deixe um pouco mesa com identificadores como

sys.message.1234.warning.A45
sys.message.1235.error.O98
....

Em seguida, você pode escrever

SELECT Source         = q.value('(/n[1])', 'varchar(10)'),
       RecordType     = q.value('(/n[2])', 'varchar(20)'),
       RecordNumber   = q.value('(/n[3])', 'int'),
       Status         = q.value('(/n[4])', 'varchar(5)')
FROM   (
         SELECT   q = Convert(xml,'<n>'+Replace(fieldName,'.','</n><n>')+'</n>')
         FROM     some_TABLE
       ) Q

divisão e lançando todas as partes.

Respondeu 11/11/2014 em 14:31
fonte usuário

votos
8

Eu uso a resposta de Frederic mas isso não funciona no SQL Server 2005

Eu modifiquei e eu estou usando select com union alle funciona

DECLARE @str varchar(max)
SET @str = 'Hello John Smith how are you'

DECLARE @separator varchar(max)
SET @separator = ' '

DECLARE @Splited table(id int IDENTITY(1,1), item varchar(max))

SET @str = REPLACE(@str, @separator, ''' UNION ALL SELECT ''')
SET @str = ' SELECT  ''' + @str + '''  ' 

INSERT IGNORE  INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

E o resultado-set é:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you
Respondeu 13/08/2013 em 16:11
fonte usuário

votos
6

No entanto, outro obter parte n'th de corda por função delimitador:

create function GetStringPartByDelimeter (
    @value as nvarchar(max),
    @delimeter as nvarchar(max),
    @position as int
) returns NVARCHAR(MAX) 
AS BEGIN
    declare @startPos as int
    declare @endPos as int
    set @endPos = -1
    while (@position > 0 and @endPos != 0) begin
        set @startPos = @endPos + 1
        set @endPos = charindex(@delimeter, @value, @startPos)

        if(@position = 1) begin
            if(@endPos = 0)
                set @endPos = len(@value) + 1

            return substring(@value, @startPos, @endPos - @startPos)
        end

        set @position = @position - 1
    end

    return null
end

eo uso:

select dbo.GetStringPartByDelimeter ('a;b;c;d;e', ';', 3)

que retorna:

c
Respondeu 08/01/2016 em 14:30
fonte usuário

votos
6

Eu estava procurando a solução na rede e as obras abaixo para mim. Ref .

E você chamar a função como esta:

SELECT * FROM dbo.split('ram shyam hari gopal',' ')

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE 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 IGNORE  INTO @temptable(Items) VALUES(@slice)       
        SET @String = RIGHT(@String,len(@String) - @idx)       
        IF len(@String) = 0 break       
    END   
    RETURN       
END
Respondeu 20/11/2011 em 07:40
fonte usuário

votos
5

O exemplo a seguir utiliza um CTE recursiva

atualização 2013/09/18

CREATE FUNCTION dbo.SplitStrings_CTE(@List nvarchar(max), @Delimiter nvarchar(1))
RETURNS @returns TABLE (val nvarchar(max), [level] int, PRIMARY KEY CLUSTERED([level]))
AS
BEGIN
;WITH cte AS
 (
  SELECT SUBSTRING(@List, 0, CHARINDEX(@Delimiter,  @List + @Delimiter)) AS val,
         CAST(STUFF(@List + @Delimiter, 1, CHARINDEX(@Delimiter, @List + @Delimiter), '') AS nvarchar(max)) AS stval, 
         1 AS [level]
  UNION ALL
  SELECT SUBSTRING(stval, 0, CHARINDEX(@Delimiter, stval)),
         CAST(STUFF(stval, 1, CHARINDEX(@Delimiter, stval), '') AS nvarchar(max)),
         [level] + 1
  FROM cte
  WHERE stval != ''
  )
  INSERT IGNORE  @returns
  SELECT REPLACE(val, ' ','' ) AS val, [level]
  FROM cte
  WHERE val > ''
  RETURN
END

Demo no SQLFiddle

Respondeu 14/03/2013 em 11:18
fonte usuário

votos
5

Tente isto:

CREATE function [SplitWordList]
(
 @list varchar(8000)
)
returns @t table 
(
 Word varchar(50) not null,
 Position int identity(1,1) not null
)
as begin
  declare 
    @pos int,
    @lpos int,
    @item varchar(100),
    @ignore varchar(100),
    @dl int,
    @a1 int,
    @a2 int,
    @z1 int,
    @z2 int,
    @n1 int,
    @n2 int,
    @c varchar(1),
    @a smallint
  select 
    @a1 = ascii('a'),
    @a2 = ascii('A'),
    @z1 = ascii('z'),
    @z2 = ascii('Z'),
    @n1 = ascii('0'),
    @n2 = ascii('9')
  set @ignore = '''"'
  set @pos = 1
  set @dl = datalength(@list)
  set @lpos = 1
  set @item = ''
  while (@pos <= @dl) begin
    set @c = substring(@list, @pos, 1)
    if (@ignore not like '%' + @c + '%') begin
      set @a = ascii(@c)
      if ((@a >= @a1) and (@a <= @z1))  
        or ((@a >= @a2) and (@a <= @z2))
        or ((@a >= @n1) and (@a <= @n2))
      begin
        set @item = @item + @c
      end else if (@item > '') begin
        insert into @t values (@item)
        set @item = ''
      end
    end 
    set @pos = @pos + 1
  end
  if (@item > '') begin
    insert into @t values (@item)
  end
  return
end

Testá-lo como este:

select * from SplitWordList('Hello John Smith')
Respondeu 05/08/2008 em 19:41
fonte usuário

votos
3


    Alter Function dbo.fn_Split
    (
    @Expression nvarchar(max),
    @Delimiter  nvarchar(20) = ',',
    @Qualifier  char(1) = Null
    )
    RETURNS @Results TABLE (id int IDENTITY(1,1), value nvarchar(max))
    AS
    BEGIN
       /* USAGE
            Select * From dbo.fn_Split('apple pear grape banana orange honeydew cantalope 3 2 1 4', ' ', Null)
            Select * From dbo.fn_Split('1,abc,"Doe, John",4', ',', '"')
            Select * From dbo.fn_Split('Hello 0,"&""&&&&', ',', '"')
       */

       -- Declare Variables
       DECLARE
          @X     xml,
          @Temp  nvarchar(max),
          @Temp2 nvarchar(max),
          @Start int,
          @End   int

       -- HTML Encode @Expression
       Select @Expression = (Select @Expression For XML Path(''))

       -- Find all occurences of @Delimiter within @Qualifier and replace with |||***|||
       While PATINDEX('%' + @Qualifier + '%', @Expression) > 0 AND Len(IsNull(@Qualifier, '')) > 0
       BEGIN
          Select
             -- Starting character position of @Qualifier
             @Start = PATINDEX('%' + @Qualifier + '%', @Expression),
             -- @Expression starting at the @Start position
             @Temp = SubString(@Expression, @Start + 1, LEN(@Expression)-@Start+1),
             -- Next position of @Qualifier within @Expression
             @End = PATINDEX('%' + @Qualifier + '%', @Temp) - 1,
             -- The part of Expression found between the @Qualifiers
             @Temp2 = Case When @End < 0 Then @Temp Else Left(@Temp, @End) End,
             -- New @Expression
             @Expression = REPLACE(@Expression,
                                   @Qualifier + @Temp2 + Case When @End < 0 Then '' Else @Qualifier End,
                                   Replace(@Temp2, @Delimiter, '|||***|||')
                           )
       END

       -- Replace all occurences of @Delimiter within @Expression with '</fn_Split><fn_Split>'
       -- And convert it to XML so we can select from it
       SET
          @X = Cast('<fn_Split>' +
                    Replace(@Expression, @Delimiter, '</fn_Split><fn_Split>') +
                    '</fn_Split>' as xml)

       -- Insert into our returnable table replacing '|||***|||' back to @Delimiter
       INSERT IGNORE  @Results
       SELECT
          "Value" = LTRIM(RTrim(Replace(C.value('.', 'nvarchar(max)'), '|||***|||', @Delimiter)))
       FROM
          @X.nodes('fn_Split') as X(C)

       -- Return our temp table
       RETURN
    END

Respondeu 05/11/2013 em 01:12
fonte usuário

votos
2

Se o seu banco de dados tem nível de compatibilidade de 130 ou superior, em seguida, você pode usar o STRING_SPLIT função juntamente com OFFSET FETCH cláusulas para obter o item específico pelo índice.

Para obter o item no índice 1, você pode usar o seguinte código

SELECT value
FROM STRING_SPLIT('Hello John Smith',' ')
ORDER BY (SELECT NULL)
OFFSET 1 ROWS
FETCH NEXT 1 ROWS ONLY

Para verificar o nível de compatibilidade do banco de dados , executar este código:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';
Respondeu 05/04/2018 em 10:23
fonte usuário

votos
2

Você pode dividir uma string em SQL sem precisar de uma função:

DECLARE @bla varchar(MAX)
SET @bla = 'BED40DFC-F468-46DD-8017-00EF2FA3E4A4,64B59FC5-3F4D-4B0E-9A48-01F3D4F220B0,A611A108-97CA-42F3-A2E1-057165339719,E72D95EA-578F-45FC-88E5-075F66FD726C'

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT 
    x.XmlCol.value('.', 'varchar(36)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE(@bla, ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol);

Se você precisa para apoiar cordas arbitrárias (com XML caracteres especiais)

DECLARE @bla NVARCHAR(MAX)
SET @bla = '<html>unsafe & safe Utf8CharsDon''tGetEncoded ÄöÜ - "Conex"<html>,Barnes & Noble,abc,def,ghi'

-- http://stackoverflow.com/questions/14712864/how-to-query-values-from-xml-nodes
SELECT 
    x.XmlCol.value('.', 'nvarchar(MAX)') AS val 
FROM 
(
    SELECT 
    CAST('<e>' + REPLACE((SELECT @bla FOR XML PATH('')), ',', '</e><e>') + '</e>' AS xml) AS RawXml
) AS b 
CROSS APPLY b.RawXml.nodes('e') x(XmlCol); 
Respondeu 23/10/2015 em 10:07
fonte usuário

votos
2

Quase todas as outras respostas código dividir estão substituindo a string sendo dividido que desperdiça ciclos de CPU e executa as alocações de memória desnecessários.

Eu cobrir uma maneira muito melhor de fazer uma divisão corda aqui: http://www.digitalruby.com/split-string-sql-server/

Aqui está o código:

SET NOCOUNT ON

-- You will want to change nvarchar(MAX) to nvarchar(50), varchar(50) or whatever matches exactly with the string column you will be searching against
DECLARE @SplitStringTable TABLE (Value nvarchar(MAX) NOT NULL)
DECLARE @StringToSplit nvarchar(MAX) = 'your|string|to|split|here'
DECLARE @SplitEndPos int
DECLARE @SplitValue nvarchar(MAX)
DECLARE @SplitDelim nvarchar(1) = '|'
DECLARE @SplitStartPos int = 1

SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)

WHILE @SplitEndPos > 0
BEGIN
    SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, (@SplitEndPos - @SplitStartPos))
    INSERT IGNORE  @SplitStringTable (Value) VALUES (@SplitValue)
    SET @SplitStartPos = @SplitEndPos + 1
    SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)
END

SET @SplitValue = SUBSTRING(@StringToSplit, @SplitStartPos, 2147483647)
INSERT IGNORE  @SplitStringTable (Value) VALUES(@SplitValue)

SET NOCOUNT OFF

-- You can select or join with the values in @SplitStringTable at this point.
Respondeu 26/08/2014 em 17:50
fonte usuário

votos
2

Eu sei que é uma questão antiga, mas acho que alguém pode se beneficiar de minha solução.

select 
SUBSTRING(column_name,1,CHARINDEX(' ',column_name,1)-1)
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name))
    ,1
    ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)-1)
,SUBSTRING(SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name))
    ,CHARINDEX(' ',SUBSTRING(column_name,CHARINDEX(' ',column_name,1)+1,LEN(column_name)),1)+1
    ,LEN(column_name))
from table_name

SQL FIDDLE

vantagens:

  • Ele separa toda a 3 sub-cordas deliminator por ''.
  • Não se deve usar enquanto loop, uma vez que diminui o desempenho.
  • Não há necessidade de Pivot como toda a sub-string resultante será exibido em um Row

limitações:

  • É preciso saber o total não. de espaços (sub-string).

Nota : a solução pode dar sub-string até a N.

Para superar a limitação, podemos usar o seguinte ref .

Mas novamente a acima solução não pode ser usado em uma tabela (Actaully eu não era capaz de usá-lo).

Mais uma vez eu espero que esta solução pode ajudar alguns e um.

Update: Em caso de Registros> 50000 não é aconselhável usar LOOPS, uma vez que irá degradar o desempenho

Respondeu 24/01/2013 em 07:43
fonte usuário

votos
1

Eu sei que é tarde, mas recentemente tive essa exigência e veio com o código abaixo. Eu não tenho uma escolha para usar a função definida pelo usuário. Espero que isto ajude.

SELECT 
    SUBSTRING(
                SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
                        ),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
            )
Respondeu 17/09/2018 em 21:07
fonte usuário

votos
1

Solução simples para analisar PRIMEIRO E SOBRENOME

DECLARE @Name varchar(10) = 'John Smith'

-- Get First Name
SELECT SUBSTRING(@Name, 0, (SELECT CHARINDEX(' ', @Name)))

-- Get Last Name
SELECT SUBSTRING(@Name, (SELECT CHARINDEX(' ', @Name)) + 1, LEN(@Name))

No meu caso (e em muitos outros, parece ...), eu tenho uma lista de nomes primeiro e último separados por um único espaço. Isso pode ser usado diretamente dentro de uma instrução SELECT para analisar primeiro e último nome.

-- i.e. Get First and Last Name from a table of Full Names
SELECT SUBSTRING(FullName, 0, (SELECT CHARINDEX(' ', FullName))) as FirstName,
SUBSTRING(FullName, (SELECT CHARINDEX(' ', FullName)) + 1, LEN(FullName)) as LastName,
From FullNameTable
Respondeu 20/08/2018 em 18:59
fonte usuário

votos
1

Aqui é uma função que irá realizar o objetivo da questão de dividir uma string e acessar o item X:

CREATE FUNCTION [dbo].[SplitString]
(
   @List       VARCHAR(MAX),
   @Delimiter  VARCHAR(255),
   @ElementNumber INT
)
RETURNS VARCHAR(MAX)
AS
BEGIN

       DECLARE @inp VARCHAR(MAX)
       SET @inp = (SELECT REPLACE(@List,@Delimiter,'_DELMTR_') FOR XML PATH(''))

       DECLARE @xml XML
       SET @xml = '<split><el>' + REPLACE(@inp,'_DELMTR_','</el><el>') + '</el></split>'

       DECLARE @ret VARCHAR(MAX)
       SET @ret = (SELECT
              el = split.el.value('.','varchar(max)')
       FROM  @xml.nodes('/split/el[string-length(.)>0][position() = sql:variable("@elementnumber")]') split(el))

       RETURN @ret

END

Uso:

SELECT dbo.SplitString('Hello John Smith', ' ', 2)

Resultado:

John
Respondeu 26/04/2018 em 21:16
fonte usuário

votos
1

A resposta de Aaron Bertrand é grande, mas imperfeito. Ele não lida com precisão um espaço como um delimitador (como foi o exemplo na pergunta original) uma vez que as tiras de função comprimento espaços à direita.

O seguinte é o seu código, com um pequeno ajuste para permitir um delimitador de espaço:

CREATE FUNCTION [dbo].[SplitString]
(
    @List NVARCHAR(MAX),
    @Delim VARCHAR(255)
)
RETURNS TABLE
AS
    RETURN ( SELECT [Value] FROM 
      ( 
        SELECT 
          [Value] = LTRIM(RTRIM(SUBSTRING(@List, [Number],
          CHARINDEX(@Delim, @List + @Delim, [Number]) - [Number])))
        FROM (SELECT Number = ROW_NUMBER() OVER (ORDER BY name)
          FROM sys.all_objects) AS x
          WHERE Number <= LEN(@List)
          AND SUBSTRING(@Delim + @List, [Number], LEN(@Delim+'x')-1) = @Delim
      ) AS y
    );
Respondeu 22/03/2018 em 14:38
fonte usuário

votos
1

Começando com SQL Server 2016 que string_split

DECLARE @string varchar(100) = 'Richard, Mike, Mark'

SELECT value FROM string_split(@string, ',')
Respondeu 04/09/2017 em 21:52
fonte usuário

votos
1

Solução baseada em conjunto puro utilizando TVFcom recursiva CTE. Você pode JOINe APPLYesta função para qualquer conjunto de dados.

create function [dbo].[SplitStringToResultSet] (@value varchar(max), @separator char(1))
returns table
as return
with r as (
    select value, cast(null as varchar(max)) [x], -1 [no] from (select rtrim(cast(@value as varchar(max))) [value]) as j
    union all
    select right(value, len(value)-case charindex(@separator, value) when 0 then len(value) else charindex(@separator, value) end) [value]
    , left(r.[value], case charindex(@separator, r.value) when 0 then len(r.value) else abs(charindex(@separator, r.[value])-1) end ) [x]
    , [no] + 1 [no]
    from r where value > '')

select ltrim(x) [value], [no] [index] from r where x is not null;
go

Uso:

select *
from [dbo].[SplitStringToResultSet]('Hello John Smith', ' ')
where [index] = 1;

Resultado:

value   index
-------------
John    1
Respondeu 13/01/2015 em 06:37
fonte usuário

votos
0

Você pode usar STRING_SPLITa função disponível no SQL Server 2016 ou posterior. Esteja ciente de que não há garantia de que os substrings será devolvido em qualquer ordem particular.

WITH testdata(id, string) AS (
    SELECT 1, NULL UNION ALL
    SELECT 2, 'a' UNION ALL
    SELECT 3, 'a b' UNION ALL
    SELECT 4, 'a b c' UNION ALL
    SELECT 5, 'a b c d'
)
SELECT testdata.id, testdata.string, (
    SELECT value AS substr FROM STRING_SPLIT(testdata.string, ' ') FOR XML PATH(''), TYPE
).value('substr[2]', 'VARCHAR(100)') AS [2nd_substr]
FROM testdata

Onde:

  • STRING_SPLIT retorna uma tabela com uma coluna chamada value
  • FOR XML PATH('') transforma as linhas para <substr>a</substr><substr>b</substr>...
  • TYPEconverte o acima, para XMLtipo de dados
  • value('substr[2]', 'VARCHAR(100)')corre expressão XPath no de cima e retorna VARCHARtipo de dados

Resultado:

| id | string  | 2nd_substr |
|----|---------|------------|
| 1  | NULL    | NULL       |
| 2  | a       | NULL       |
| 3  | a b     | b          |
| 4  | a b c   | b          |
| 5  | a b c d | b          |
Respondeu 24/01/2018 em 12:27
fonte usuário

votos
0

A abordagem moderna usando STRING_SPLIT , requer SQL Server 2016 e acima.

DECLARE @string varchar(100) = 'Hello John Smith'

SELECT
    ROW_NUMBER() OVER (ORDER BY value) AS RowNr,
    value
FROM string_split(@string, ' ')

Resultado:

RowNr   value
1       Hello
2       John
3       Smith

Agora é possível obter th enésimo elemento do número da linha.

Respondeu 02/01/2018 em 15:02
fonte usuário

votos
0

prédio na solução @NothingsImpossible, ou melhor, comentar sobre a resposta mais votada (logo abaixo o aceita), eu encontrei o seguinte rápida e suja solução cumprir minhas próprias necessidades - tem uma vantagem de ser o único dentro do domínio SQL.

dada uma string "primeiro, o segundo, o terceiro, em quarto lugar, o quinto", digamos, eu quero começar o terceiro token. isso funciona somente se sabemos quantas fichas a corda vai ter - neste caso é 5. assim a minha forma de ação é para cortar as duas últimas fichas afastado (consulta interna), e depois de cortar as duas primeiras fichas de distância ( consulta externa)

Eu sei que isso é feio e abrange as condições específicas em que estava, mas estou postando isso apenas no caso de alguém acha útil. Felicidades

select 
    REVERSE(
        SUBSTRING(
            reverse_substring, 
            0, 
            CHARINDEX(';', reverse_substring)
        )
    ) 
from 
(
    select 
        msg,
        SUBSTRING(
            REVERSE(msg), 
            CHARINDEX(
                ';', 
                REVERSE(msg), 
                CHARINDEX(
                    ';',
                    REVERSE(msg)
                )+1
            )+1,
            1000
        ) reverse_substring
    from 
    (
        select 'first;second;third;fourth;fifth' msg
    ) a
) b
Respondeu 31/10/2016 em 14:18
fonte usuário

votos
0
declare @strng varchar(max)='hello john smith'
select (
    substring(
        @strng,
        charindex(' ', @strng) + 1,
        (
          (charindex(' ', @strng, charindex(' ', @strng) + 1))
          - charindex(' ',@strng)
        )
    ))
Respondeu 14/07/2016 em 05:29
fonte usuário

votos
0

I devoloped isso,

declare @x nvarchar(Max) = 'ali.veli.deli.';
declare @item nvarchar(Max);
declare @splitter char='.';

while CHARINDEX(@splitter,@x) != 0
begin
    set @item = LEFT(@x,CHARINDEX(@splitter,@x))
    set @x    = RIGHT(@x,len(@x)-len(@item) )
     select @item as item, @x as x;
end

a única atenção que você deve é ​​ponto '' que final do @x é sempre deveria estar lá.

Respondeu 15/10/2015 em 10:50
fonte usuário

votos
0

se alguém quiser obter apenas uma parte do texto seperatured pode usar este

SELECT * FROM fromSplitStringSep ( 'WORD1 wordr2 word3',' ')

CREATE function [dbo].[SplitStringSep] 
(
    @str nvarchar(4000), 
    @separator char(1)
)
returns table
AS
return (
    with tokens(p, a, b) AS (
        select 
        1, 
        1, 
        charindex(@separator, @str)
        union all
        select
            p + 1, 
            b + 1, 
            charindex(@separator, @str, b + 1)
        from tokens
        where b > 0
        )
        select
            p-1 zeroBasedOccurance,
            substring(
                @str, 
                a, 
                case when b > 0 then b-a ELSE 4000 end) 
            AS s
        from tokens
  )
Respondeu 13/02/2015 em 09:14
fonte usuário

votos
0
CREATE FUNCTION [dbo].[fnSplitString] 
( 
    @string NVARCHAR(MAX), 
    @delimiter CHAR(1) 
) 
RETURNS @output TABLE(splitdata NVARCHAR(MAX) 
) 
BEGIN 
    DECLARE @start INT, @end INT 
    SELECT @start = 1, @end = CHARINDEX(@delimiter, @string) 
    WHILE @start < LEN(@string) + 1 BEGIN 
        IF @end = 0  
            SET @end = LEN(@string) + 1

        INSERT IGNORE  INTO @output (splitdata)  
        VALUES(SUBSTRING(@string, @start, @end - @start)) 
        SET @start = @end + 1 
        SET @end = CHARINDEX(@delimiter, @string, @start)

    END 
    RETURN 
END

E usá-lo

select *from dbo.fnSplitString('Querying SQL Server','')
Respondeu 20/12/2014 em 11:58
fonte usuário

votos
0

enquanto semelhante à resposta baseada em XML por josejuan, descobri que o processamento do caminho xml apenas uma vez, em seguida, pivotante foi moderadamente mais eficiente:

select ID,
    [3] as PathProvidingID,
    [4] as PathProvider,
    [5] as ComponentProvidingID,
    [6] as ComponentProviding,
    [7] as InputRecievingID,
    [8] as InputRecieving,
    [9] as RowsPassed,
    [10] as InputRecieving2
    from
    (
    select id,message,d.* from sysssislog cross apply       ( 
          SELECT Item = y.i.value('(./text())[1]', 'varchar(200)'),
              row_number() over(order by y.i) as rn
          FROM 
          ( 
             SELECT x = CONVERT(XML, '<i>' + REPLACE(Message, ':', '</i><i>') + '</i>').query('.')
          ) AS a CROSS APPLY x.nodes('i') AS y(i)
       ) d
       WHERE event
       = 
       'OnPipelineRowsSent'
    ) as tokens 
    pivot 
    ( max(item) for [rn] in ([3],[4],[5],[6],[7],[8],[9],[10]) 
    ) as data

correu em 08:30

select id,
tokens.value('(/n[3])', 'varchar(100)')as PathProvidingID,
tokens.value('(/n[4])', 'varchar(100)') as PathProvider,
tokens.value('(/n[5])', 'varchar(100)') as ComponentProvidingID,
tokens.value('(/n[6])', 'varchar(100)') as ComponentProviding,
tokens.value('(/n[7])', 'varchar(100)') as InputRecievingID,
tokens.value('(/n[8])', 'varchar(100)') as InputRecieving,
tokens.value('(/n[9])', 'varchar(100)') as RowsPassed
 from
(
    select id, Convert(xml,'<n>'+Replace(message,'.','</n><n>')+'</n>') tokens
         from sysssislog 
       WHERE event
       = 
       'OnPipelineRowsSent'
    ) as data

correu em 09:20

Respondeu 08/12/2014 em 03:59
fonte usuário

votos
0

Solução CTE recursiva com dor servidor, testá-lo

MS SQL Server 2008 Setup Schema :

create table Course( Courses varchar(100) );
insert into Course values ('Hello John Smith');

Consulta 1 :

with cte as
   ( select 
        left( Courses, charindex( ' ' , Courses) ) as a_l,
        cast( substring( Courses, 
                         charindex( ' ' , Courses) + 1 , 
                         len(Courses ) ) + ' ' 
              as varchar(100) )  as a_r,
        Courses as a,
        0 as n
     from Course t
    union all
      select 
        left(a_r, charindex( ' ' , a_r) ) as a_l,
        substring( a_r, charindex( ' ' , a_r) + 1 , len(a_R ) ) as a_r,
        cte.a,
        cte.n + 1 as n
    from Course t inner join cte 
         on t.Courses = cte.a and len( a_r ) > 0

   )
select a_l, n from cte
--where N = 1

resultados :

|    A_L | N |
|--------|---|
| Hello  | 0 |
|  John  | 1 |
| Smith  | 2 |
Respondeu 16/01/2014 em 11:38
fonte usuário

votos
0

Isso é algo que eu fiz, a fim de obter um token específico em uma corda. (Testado em MSSQL 2008)

Em primeiro lugar, criando as seguintes funções: (encontrado em: aqui

CREATE FUNCTION dbo.SplitStrings_Moden
(
   @List NVARCHAR(MAX),
   @Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
  WITH E1(N)        AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
       E2(N)        AS (SELECT 1 FROM E1 a, E1 b),
       E4(N)        AS (SELECT 1 FROM E2 a, E2 b),
       E42(N)       AS (SELECT 1 FROM E4 a, E2 b),
       cteTally(N)  AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
                         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
       cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
                         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
  SELECT Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
    FROM cteStart s;

e

create FUNCTION dbo.getToken
(
@List NVARCHAR(MAX),
@Delimiter NVARCHAR(255),
@Pos int
)
RETURNS varchar(max)
as 
begin
declare @returnValue varchar(max);
select @returnValue = tbl.Item from (
select ROW_NUMBER() over (order by (select null)) as id, * from dbo.SplitStrings_Moden(@List, @Delimiter)
) as tbl
where tbl.id = @Pos
return @returnValue
end

então você pode usá-lo assim:

select dbo.getToken('1111_2222_3333_', '_', 1)

que retornam 1111

Respondeu 25/07/2013 em 12:07
fonte usuário

votos
0

Bem, a minha não é tão simples, mas aqui está o código que eu uso para dividir uma variável de entrada delimitada por vírgula em valores individuais, e colocá-lo em uma variável de tabela. Tenho certeza que você poderia modificar este ligeiramente para dividir com base em um espaço e, em seguida, fazer uma consulta SELECT básica contra essa variável tabela para obter seus resultados.

-- Create temporary table to parse the list of accounting cycles.
DECLARE @tblAccountingCycles table
(
    AccountingCycle varchar(10)
)

DECLARE @vchAccountingCycle varchar(10)
DECLARE @intPosition int

SET @vchAccountingCycleIDs = LTRIM(RTRIM(@vchAccountingCycleIDs)) + ','
SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)

IF REPLACE(@vchAccountingCycleIDs, ',', '') <> ''
BEGIN
    WHILE @intPosition > 0
    BEGIN
        SET @vchAccountingCycle = LTRIM(RTRIM(LEFT(@vchAccountingCycleIDs, @intPosition - 1)))
        IF @vchAccountingCycle <> ''
        BEGIN
            INSERT IGNORE  INTO @tblAccountingCycles (AccountingCycle) VALUES (@vchAccountingCycle)
        END
        SET @vchAccountingCycleIDs = RIGHT(@vchAccountingCycleIDs, LEN(@vchAccountingCycleIDs) - @intPosition)
        SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)
    END
END

O conceito é praticamente o mesmo. Uma outra alternativa é aproveitar a compatibilidade .NET dentro do SQL Server 2005 em si. Você pode essencialmente escrever-se um método simples em .NET que iria dividir a corda e, em seguida, expor isso como um procedimento / função armazenada.

Respondeu 05/08/2008 em 19:36
fonte usuário

votos
-1

Estou usando a resposta de vzczc usando recursiva CTE de há algum tempo, mas queria atualizá-lo para lidar com um separador de comprimento variável e também para lidar com cordas com condução e de retardamento "separadores", como quando você tem um arquivo CSV com os registros como :

"Bob", "Smith", "Sunnyvale", "CA"

ou quando você está lidando com Fqn de seis peças, como mostrado abaixo. Eu usá-los extensivamente para o registo do subject_fqn para auditoria, tratamento de erros, etc. e ParseName lida apenas com quatro partes:

[netbios_name].[machine_name].[instance].[database].[schema].[table].[column]

Aqui é a minha versão atualizada, e graças a vzczc de para seu posto original!

select * from [utility].[split_string](N'"this"."string"."gets"."split"."and"."removes"."leading"."and"."trailing"."quotes"', N'"."', N'"', N'"');

select * from [utility].[split_string](N'"this"."string"."gets"."split"."but"."leaves"."leading"."and"."trailing"."quotes"', N'"."', null, null);

select * from [utility].[split_string](N'[netbios_name].[machine_name].[instance].[database].[schema].[table].[column]', N'].[', N'[', N']');

create function [utility].[split_string] ( 
  @input       [nvarchar](max) 
  , @separator [sysname] 
  , @lead      [sysname] 
  , @lag       [sysname]) 
returns @node_list table ( 
  [index]  [int] 
  , [node] [nvarchar](max)) 
  begin 
      declare @separator_length [int]= len(@separator) 
              , @lead_length    [int] = isnull(len(@lead), 0) 
              , @lag_length     [int] = isnull(len(@lag), 0); 
      -- 
      set @input = right(@input, len(@input) - @lead_length); 
      set @input = left(@input, len(@input) - @lag_length); 
      -- 
      with [splitter]([index], [starting_position], [start_location]) 
           as (select cast(@separator_length as [bigint]) 
                      , cast(1 as [bigint]) 
                      , charindex(@separator, @input) 
               union all 
               select [index] + 1 
                      , [start_location] + @separator_length 
                      , charindex(@separator, @input, [start_location] + @separator_length) 
               from   [splitter] 
               where  [start_location] > 0) 
      -- 
      insert into @node_list 
                  ([index],[node]) 
        select [index] - @separator_length                   as [index] 
               , substring(@input, [starting_position], case 
                                                            when [start_location] > 0 
                                                                then 
                                                              [start_location] - [starting_position] 
                                                            else 
                                                              len(@input) 
                                                        end) as [node] 
        from   [splitter]; 
      -- 
      return; 
  end; 
go 
Respondeu 19/08/2014 em 20:45
fonte usuário

votos
-1

Um simples algoritmo otimizado:

ALTER FUNCTION [dbo].[Split]( @Text NVARCHAR(200),@Splitor CHAR(1) )
RETURNS @Result TABLE ( value NVARCHAR(50)) 
AS
BEGIN
    DECLARE @PathInd INT
    Set @Text+=@Splitor
    WHILE LEN(@Text) > 0
    BEGIN
        SET @PathInd=PATINDEX('%'+@Splitor+'%',@Text)
        INSERT IGNORE  INTO  @Result VALUES(SUBSTRING(@Text, 0, @PathInd))
        SET @Text= SUBSTRING(@Text, @PathInd+1, LEN(@Text))
    END
        RETURN 
END
Respondeu 01/05/2014 em 07:26
fonte usuário

votos
-1

Aqui está uma UDF SQL que pode dividir uma string e agarrar apenas uma determinada peça.

create FUNCTION [dbo].[udf_SplitParseOut]
(
    @List nvarchar(MAX),
    @SplitOn nvarchar(5),
    @GetIndex smallint
)  
returns varchar(1000)
AS  

BEGIN

DECLARE @RtnValue table 
(

    Id int identity(0,1),
    Value nvarchar(MAX)
) 


    DECLARE @result varchar(1000)

    While (Charindex(@SplitOn,@List)>0)
    Begin
        Insert Into @RtnValue (value)
        Select Value = ltrim(rtrim(Substring(@List,1,Charindex(@SplitOn,@List)-1)))
        Set @List = Substring(@List,Charindex(@SplitOn,@List)+len(@SplitOn),len(@List))
    End

    Insert Into @RtnValue (Value)
    Select Value = ltrim(rtrim(@List))

    select @result = value from @RtnValue where ID = @GetIndex

    Return @result
END
Respondeu 20/03/2014 em 15:41
fonte usuário

votos
-1

Aqui está a minha solução que pode ajudar alguém. Modificação da resposta de Jonesinator acima.

Se eu tiver uma seqüência de valores INT delimitados e quer uma tabela de INTs devolvidos (Que eu possa, em seguida, juntar-se diante). por exemplo, '1,20,3,343,44,6,8765'

Criar um UDF:

IF OBJECT_ID(N'dbo.ufn_GetIntTableFromDelimitedList', N'TF') IS NOT NULL
    DROP FUNCTION dbo.[ufn_GetIntTableFromDelimitedList];
GO

CREATE FUNCTION dbo.[ufn_GetIntTableFromDelimitedList](@String NVARCHAR(MAX),                 @Delimiter CHAR(1))

RETURNS @table TABLE 
(
    Value INT NOT NULL
)
AS 
BEGIN
DECLARE @Pattern NVARCHAR(3)
SET @Pattern = '%' + @Delimiter + '%'
DECLARE @Value NVARCHAR(MAX)

WHILE LEN(@String) > 0
    BEGIN
        IF PATINDEX(@Pattern, @String) > 0
        BEGIN
            SET @Value = SUBSTRING(@String, 0, PATINDEX(@Pattern, @String))
            INSERT IGNORE  INTO @table (Value) VALUES (@Value)

            SET @String = SUBSTRING(@String, LEN(@Value + @Delimiter) + 1, LEN(@String))
        END
        ELSE
        BEGIN
            -- Just the one value.
            INSERT IGNORE  INTO @table (Value) VALUES (@String)
            RETURN
        END
    END

RETURN
END
GO

Em seguida, obter os resultados da tabela:

SELECT * FROM dbo.[ufn_GetIntTableFromDelimitedList]('1,20,3,343,44,6,8765', ',')

1
20
3
343
44
6
8765

E em uma junção declaração:

SELECT [ID], [FirstName]
FROM [User] u
JOIN dbo.[ufn_GetIntTableFromDelimitedList]('1,20,3,343,44,6,8765', ',') t ON u.[ID] = t.[Value]

1    Elvis
20   Karen
3    David
343  Simon
44   Raj
6    Mike
8765 Richard

Se você quiser retornar uma lista de NVARCHARs em vez de INTs em seguida, basta alterar a definição da tabela:

RETURNS @table TABLE 
(
    Value NVARCHAR(MAX) NOT NULL
)
Respondeu 20/06/2013 em 00:42
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more