Comment puis-je découper une chaîne pour que je puisse accéder à l'article x?

voix
442

En utilisant SQL Server, comment découper une chaîne pour que je puisse accéder à l'article x?

Prenez une chaîne « Bonjour John Smith ». Comment puis-je diviser la chaîne par l'espace et accéder à l'élément à l'index 1 qui devrait retourner « John »?

Créé 05/08/2008 à 19:15
source utilisateur
Dans d'autres langues...                            


42 réponses

voix
335

Je ne crois pas SQL Server a une fonction split intégré, donc autre qu'une UDF, la seule autre réponse que je sais est de détourner la fonction ParseName:

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

ParseName prend une chaîne et il se divise sur le caractère de la période. Il faut un certain nombre en tant que second argument, et ce nombre indique le segment de la chaîne de retour (en fonction de l'arrière vers l'avant).

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

problème évident est lorsque la chaîne contient déjà une période. Je pense toujours à l'aide d'une UDF est la meilleure façon ... d'autres suggestions?

Créé 05/08/2008 à 19:45
source utilisateur

voix
177

Vous pouvez trouver la solution dans SQL Fonction définie par l'utilisateur parser une chaîne Délimité utile ( à partir du Code du projet ).

Vous pouvez utiliser cette logique simple:

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
Créé 05/08/2008 à 19:28
source utilisateur

voix
106

Tout d'abord, créer une fonction (en utilisant CTE, expression de table commune supprime la nécessité d'une table temporaire)

 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

Ensuite, l'utiliser comme une table (ou de le modifier pour tenir dans votre procédure stockée existante) comme celui-ci.

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

Mettre à jour

version précédente échouerait pour une chaîne d'entrée plus de 4000 caractères. Cette version prend en charge la limitation:

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

Utilisation reste le même.

Créé 05/08/2008 à 19:57
source utilisateur

voix
51

La plupart des solutions utilisent ici en boucles ou récursifs CTEs. Une approche ensembliste sera supérieure, je vous le promets:

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
        );

En savoir plus sur les fonctions fractionnés, pourquoi (et la preuve que) tout en boucles et récursives ne CTEs pas à l'échelle, et de meilleures alternatives, si les chaînes de fractionnement provenant de la couche d'application:

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

Créé 12/11/2013 à 18:16
source utilisateur

voix
37

Vous pouvez tirer parti d'une table numérique pour faire l'analyse syntaxique de la chaîne.

Créer une table de nombres physique:

    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

Créer table de test avec 1000000 lignes

    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

Créer la fonction

    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

Utilisation (sorties 3mil lignes 40s sur mon ordinateur portable)

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

nettoyer

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

La performance est ici pas étonnant, mais appeler une fonction plus d'un million table de ligne n'est pas la meilleure idée. Si vous effectuez une chaîne répartie sur plusieurs lignes, j'éviter la fonction.

Créé 27/10/2008 à 17:48
source utilisateur

voix
20

Voici une UDF qui le fera. Il retourne une table des valeurs délimitées, n'ont pas essayé tous les scénarios sur elle, mais votre exemple fonctionne très bien.


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

Vous appelleriez comme ceci:


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

Edit: solution Mise à jour pour gérer delimters avec un len> 1 comme dans:


select * From SplitString('Hello**John**Smith','**')
Créé 05/08/2008 à 19:39
source utilisateur

voix
16

Aucun code, mais lisez l'article définitif sur ce sujet . Toutes les solutions dans d' autres réponses sont des arômes de ceux mentionnés dans cet article: tableaux et listes dans SQL Server 2005 et au - delà

Personnellement, je l'ai utilisé une solution de table chiffres le plus souvent parce qu'il convient ce que je dois faire ...

Créé 26/09/2010 à 14:44
source utilisateur

voix
15

Ici, je posterai une façon simple de la solution

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


Exécutez la fonction comme celui-ci

  select * from dbo.split('Hello John Smith',' ')
Créé 30/01/2013 à 10:41
source utilisateur

voix
12

Cette question est pas une approche de répartition de chaîne , mais de la façon d'obtenir l'élément n - ième .

Toutes les réponses ici font une sorte de division de chaîne en utilisant récursion, CTEs, multiple CHARINDEX, REVERSEet PATINDEX, en inventant des fonctions, exigent des méthodes CLR, tableaux de nombres, CROSS APPLYs ... La plupart des réponses couvrent de nombreuses lignes de code.

Mais - si vous vraiment voulez rien de plus qu'une approche pour obtenir le n - ième élément - cela peut se faire en vrai-liner , pas UDF, même pas un sous-select ... Et comme un avantage supplémentaire: SÛR type

Obtenez partie 2 délimité par un espace:

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)')

Bien sûr , vous pouvez utiliser des variables pour delimiter et la position (utilisez sql:columnpour récupérer la position directement à partir de la valeur d'une requête):

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)')

Si votre chaîne peut inclure des caractères interdits ( en particulier l' un d' entre &><), vous pouvez toujours le faire de cette façon. Il suffit d' utiliser FOR XML PATHvotre première chaîne pour remplacer tous les caractères interdits par la séquence d'échappement approprié implicitement.

Il est un cas très particulier , si - en outre - délimiteur est le point - virgule . Dans ce cas , je remplace le délimiteur premier à « # DLMT # », et le remplacer aux balises XML enfin:

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)');
Créé 08/07/2016 à 20:41
source utilisateur

voix
10

Qu'en est- il l' utilisation stringet values()déclaration?

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

Jeu de résultats obtenu.

id  item
1   Hello
2   John
3   Smith
Créé 01/03/2013 à 17:26
source utilisateur

voix
10

À mon avis, vous faites les gars ce trop compliqué. Il suffit de créer une UDF CLR et être fait avec elle.

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()));
  }
};
Créé 19/07/2012 à 22:46
source utilisateur

voix
8

Ce modèle fonctionne très bien et vous pouvez généraliser

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

noter FIELD , INDEX et TYPE .

Laissez une table avec des identifiants comme

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

Ensuite, vous pouvez écrire

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

le fractionnement et la coulée toutes les parties.

Créé 11/11/2014 à 14:31
source utilisateur

voix
8

J'utilise la réponse de frederic, mais cela ne fonctionne pas dans SQL Server 2005

Je l' ai modifié et je me sers selectavec union allet il fonctionne

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

Et le jeu de résultats est le suivant:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you
Créé 13/08/2013 à 16:11
source utilisateur

voix
6

Une autre obtenir une partie de la chaîne par n'th fonction délimiteur:

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

et l'utilisation:

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

qui retourne:

c
Créé 08/01/2016 à 14:30
source utilisateur

voix
6

Je cherchais la solution sur le net et les travaux ci - dessous pour moi. Réf .

Et vous appelez la fonction comme ceci:

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
Créé 20/11/2011 à 07:40
source utilisateur

voix
5

L'exemple suivant utilise un CTE récursive

Mise à jour 18/09/2013

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

Démo SQLFiddle

Créé 14/03/2013 à 11:18
source utilisateur

voix
5

Essaye ça:

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

Testez comme ceci:

select * from SplitWordList('Hello John Smith')
Créé 05/08/2008 à 19:41
source utilisateur

voix
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

Créé 05/11/2013 à 01:12
source utilisateur

voix
2

Si votre base de données a le niveau de compatibilité de 130 ou plus, vous pouvez utiliser la STRING_SPLIT fonction avec OFFSET FETCH clauses pour obtenir l'élément spécifique par index.

Pour obtenir l'élément à l'index 1, vous pouvez utiliser le code suivant

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

Pour vérifier le niveau de compatibilité de votre base de données , exécutez ce code:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';
Créé 05/04/2018 à 10:23
source utilisateur

voix
2

Vous pouvez diviser une chaîne en SQL sans avoir besoin d'une fonction:

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);

Si vous avez besoin pour supporter des chaînes arbitraires (avec xml caractères spéciaux)

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); 
Créé 23/10/2015 à 10:07
source utilisateur

voix
2

Presque toutes les autres réponses de code divisé remplacent la chaîne étant divisé qui gaspille cycles de CPU et effectue les allocations de mémoire inutiles.

Je couvre une bien meilleure façon de faire une scission de chaîne ici: http://www.digitalruby.com/split-string-sql-server/

Voici le code:

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.
Créé 26/08/2014 à 17:50
source utilisateur

voix
2

Je sais que c'est une vieille question, mais je pense que quelqu'un peut profiter de ma solution.

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 VIOLON

avantages:

  • Il sépare tous les 3 sous-chaînes deliminator par « ».
  • Il ne faut pas utiliser en boucle, car elle diminue la performance.
  • Pas besoin de pivoter comme tous les sous-chaîne résultante sera affichée dans une ligne

Limites:

  • Il faut connaître le pas totale. des espaces (sous-chaîne).

Remarque : la solution peut donner sous-chaîne jusqu'à N.

Pour vainquit la limitation , nous pouvons utiliser les éléments suivants ref .

Mais encore une fois ce qui précède la solution ne peut pas être utilisé dans une table (Actaully je ne pouvais l'utiliser).

Encore une fois j'espère que cette solution peut aider certains un.

Mise à jour: Dans le cas des enregistrements> il n'est pas 50000 souhaitable d'utiliser LOOPScomme il dégradera la performance

Créé 24/01/2013 à 07:43
source utilisateur

voix
1

SOLUTION SIMPLE ET pour parser PREMIER NOM

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))

Dans mon cas (et dans beaucoup d'autres, il semble ...), j'ai une liste des noms et prénoms séparés par un seul espace. Cela peut être utilisé directement dans une instruction select pour analyser d'abord et nom de famille.

-- 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
Créé 20/08/2018 à 18:59
source utilisateur

voix
1

Voici une fonction qui permettra d'atteindre l'objectif de diviser une chaîne de la question et l'accès à l'article 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

Usage:

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

Résultat:

John
Créé 26/04/2018 à 21:16
source utilisateur

voix
1

La réponse d'Aaron Bertrand est grande, mais imparfait. Il ne gère pas correctement un espace comme séparateur (tout comme l'exemple dans la question initiale) étant donné que les bandes de fonction de la longueur des espaces de fin.

Ce qui suit est son code, avec un petit ajustement pour permettre un séparateur d'espace:

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
    );
Créé 22/03/2018 à 14:38
source utilisateur

voix
1

A partir de SQL Server 2016 nous string_split

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

SELECT value FROM string_split(@string, ',')
Créé 04/09/2017 à 21:52
source utilisateur

voix
1

Solution à base de jeu pur en utilisant TVFavec récursive CTE. Vous pouvez JOINet APPLYcette fonction à un ensemble de données.

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

Usage:

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

Résultat:

value   index
-------------
John    1
Créé 13/01/2015 à 06:37
source utilisateur

voix
0

Vous pouvez utiliser la STRING_SPLITfonction disponible dans SQL Server 2016 ou version ultérieure. Sachez qu'il n'y a aucune garantie que les sous - chaînes seront retournées dans un ordre particulier.

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

Où:

  • STRING_SPLIT renvoie une table avec une colonne appelée value
  • FOR XML PATH('') transforme les lignes à <substr>a</substr><substr>b</substr>...
  • TYPEconvertit le dessus XMLtype_données
  • value('substr[2]', 'VARCHAR(100)')court expression XPath au - dessus et retourne VARCHARdatatype

Résultat:

| 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          |
Créé 24/01/2018 à 12:27
source utilisateur

voix
0

Une approche moderne en utilisant STRING_SPLIT , nécessite SQL Server 2016 et plus.

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

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

Résultat:

RowNr   value
1       Hello
2       John
3       Smith

Maintenant, il est possible d'obtenir e n-ième élément du numéro de la ligne.

Créé 02/01/2018 à 15:02
source utilisateur

voix
0

la construction sur la solution @NothingsImpossible, ou plutôt commenter la réponse la plus voté (juste en dessous de l'accepter un), j'ai trouvé ce qui suit rapide et sale solution satisfaire mes propres besoins - il a un avantage d'être uniquement dans le domaine SQL.

d'une chaîne « première, deuxième, troisième, quatrième, cinquième », disons, je veux obtenir le troisième jeton. cela ne fonctionne que si nous savons combien de jetons la chaîne va avoir - dans ce cas, il est 5. donc mon mode d'action est de couper les deux derniers jetons loin (requête interne), puis de couper les deux premiers jetons loin ( requête externe)

Je sais que cela est laid et couvre les conditions particulières que j'étais, mais je posterai juste au cas où quelqu'un le trouve utile. à votre santé

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
Créé 31/10/2016 à 14:18
source utilisateur

voix
0
declare @strng varchar(max)='hello john smith'
select (
    substring(
        @strng,
        charindex(' ', @strng) + 1,
        (
          (charindex(' ', @strng, charindex(' ', @strng) + 1))
          - charindex(' ',@strng)
        )
    ))
Créé 14/07/2016 à 05:29
source utilisateur

voix
0

Je devoloped cela,

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

la seule attention que vous devriez est point « » cette fin du @x est toujours devrait être là.

Créé 15/10/2015 à 10:50
source utilisateur

voix
0

si quelqu'un veut faire une seule partie du texte seperatured peut utiliser

select * from fromSplitStringSep ( 'mot1 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
  )
Créé 13/02/2015 à 09:14
source utilisateur

voix
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

ET UTILISER

select *from dbo.fnSplitString('Querying SQL Server','')
Créé 20/12/2014 à 11:58
source utilisateur

voix
0

tout semblable à la réponse basée sur XML par josejuan, je l'ai trouvé que le traitement du chemin xml une seule fois, puis en faisant pivoter était modérément plus efficace:

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

a couru à 08h30

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

a couru en 9h20

Créé 08/12/2014 à 03:59
source utilisateur

voix
0

Solution CTE récursive avec la douleur du serveur, testez

MS SQL Server 2008 Configuration du schéma :

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

Requête 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

résultats :

|    A_L | N |
|--------|---|
| Hello  | 0 |
|  John  | 1 |
| Smith  | 2 |
Créé 16/01/2014 à 11:38
source utilisateur

voix
0

C'est quelque chose que je l'ai fait afin d'obtenir un jeton spécifique dans une chaîne. (Testé en MSSQL 2008)

Tout d' abord, créer les fonctions suivantes: (Résultats: ici

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;

et

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

alors vous pouvez l'utiliser comme ça:

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

qui renvoient 1111

Créé 25/07/2013 à 12:07
source utilisateur

voix
0

Eh bien, le mien est pas du tout simple, mais voici le code que j'utilise pour diviser une variable d'entrée délimitée par des virgules dans des valeurs individuelles, et le mettre dans une variable de table. Je suis sûr que vous pouvez modifier légèrement ce à Split en fonction d'un espace, puis de faire une requête SELECT de base contre cette variable de table pour obtenir vos résultats.

-- 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

Le concept est à peu près la même chose. Une autre alternative consiste à tirer parti de la compatibilité .NET dans SQL Server 2005 lui-même. Vous pouvez écrire vous-même essentiellement une méthode simple dans .NET qui diviserait la chaîne, puis exposer que comme une procédure / fonction stockée.

Créé 05/08/2008 à 19:36
source utilisateur

voix
-1

Je me sers de la réponse de vzczc à l'aide cte récursive est pour un certain temps, mais ils ont voulu le mettre à jour pour gérer un séparateur de longueur variable et aussi à gérer les chaînes avec avance et en retard « séparateurs » tels que lorsque vous avez un fichier csv avec des documents tels que :

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

ou lorsque vous avez affaire à six années partie FQN comme indiqué ci-dessous. Je les utilise largement pour l'enregistrement de l'subject_fqn pour l'audit, la gestion des erreurs, etc. et ParseName poignées seulement quatre parties:

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

Voici ma version mise à jour, et grâce à des années vzczc pour son poste d'origine!

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 
Créé 19/08/2014 à 20:45
source utilisateur

voix
-1

Un algorithme simple optimisé:

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
Créé 01/05/2014 à 07:26
source utilisateur

voix
-1

Voici une UDF SQL qui peut diviser une chaîne et saisir juste une certaine pièce.

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
Créé 20/03/2014 à 15:41
source utilisateur

voix
-1

Voici ma solution qui peut aider quelqu'un. Modification de la réponse de Jonesinator ci-dessus.

Si j'ai une chaîne de valeurs INT et que vous souhaitez une délimitées table des INTs est revenu (que je peux ensuite rejoindre sur). par exemple « 1,20,3,343,44,6,8765 »

Créer une 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

Ensuite, obtenir les résultats de la table:

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

1
20
3
343
44
6
8765

Et dans une jointure déclaration:

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

Si vous voulez retourner une liste de NVARCHARs au lieu de INTs puis juste changer la définition de la table:

RETURNS @table TABLE 
(
    Value NVARCHAR(MAX) NOT NULL
)
Créé 20/06/2013 à 00:42
source utilisateur

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