Frage

Using SQL Server, how do I split a string so I can access item x?

Take a string "Hello John Smith".Wie kann ich split the string by space and access the item at index 1 sollte return "John"?

War es hilfreich?

Lösung

Sie finden die Lösung in SQL-Benutzer-Definiert Funktion Analysiert eine durch Trennzeichen Getrennte Zeichenfolge hilfreich (aus Das Code-Projekt).

Sie können mit diesem einfachen Logik:

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

Andere Tipps

Ich glaube nicht, dass SQL Server verfügt über eine integrierte split-Funktion, also andere als eine UDF, die einzige andere Antwort, die ich weiß, ist, entführen die PARSENAME Funktion:

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

PARSENAME nimmt eine Zeichenfolge und spaltet es auf den Punkt.Sie nimmt eine Zahl als zweites argument, und diese Zahl gibt an, welches segment der Zeichenfolge zurück (die Arbeit von vorne nach hinten).

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

Offensichtliches problem ist, wenn der string bereits einen Punkt enthält.Ich denke immer noch mit einem UDF ist der beste Weg...andere Vorschläge?

Erstellen Sie zunächst eine Funktion (mit CTE, common table expression nicht mit der Notwendigkeit für eine temp-Tabelle)

 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

Dann verwenden Sie es wie jede Tabelle (oder ändern Sie es zu passen in Ihre vorhandene gespeicherte Prozedur) wie dieser.

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

Update

Vorherige version würde nicht für Eingabe-Zeichenfolge länger als 4000 Zeichen.Diese version kümmert sich um die Beschränkung:

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

Die Nutzung bleibt die gleiche.

Die meisten Lösungen, die Sie hier verwenden, while-Schleifen oder rekursiven CTEs.Eine set-basierte Ansatz überlegen sein, ich verspreche es:

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

Mehr auf split-Funktionen, warum (und der Beweis, dass), während Schleifen und rekursive CTEs nicht skalierbar, und bessere alternativen, wenn splitting strings kommen aus der Anwendungsschicht:

Auf SQL Server 2016 oder höher, allerdings sollte man sich ansehen, STRING_SPLIT() und STRING_AGG():

Nutzen Sie eine Reihe Tabelle zu tun, die die Zeichenfolge analysieren.

Erstellen Sie eine physische zahlen Tabelle:

    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

Erstellen von test-Tabelle mit 1000000 Zeilen

    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

Erstellen Sie die Funktion

    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

Nutzung (Ausgänge 3mil Zeilen in den 40er Jahren auf meinem laptop)

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

cleanup

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

Performance hier ist nicht erstaunlich, aber das aufrufen einer Funktion über eine million Zeilen der Tabelle ist nicht die beste Idee.Wenn Sie einen string aufteilen, die über viele Zeilen würde ich vermeiden, die Funktion.

Diese Frage ist nicht über einen string-split-Ansatz, aber ungefähr wie man das N-te element.

Alle Antworten hier tun einige Art von string-splitting mit Rekursion, CTEs, mehrere CHARINDEX, REVERSE und PATINDEX, erfinden-Funktionen aufrufen, für die CLR-Methoden, Anzahl Tische, CROSS APPLYs ...Die meisten Antworten decken viele Zeilen code.

Aber wenn du das wirklich will nichts mehr, als ein Ansatz, um das N-te element - dies kann durchgeführt werden als real one-liner, keine UDF, nicht einmal eine sub-wählen Sie...Und als extra-Vorteil: sichere Typ

Teil 2 durch ein Leerzeichen getrennt:

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

Natürlich Sie können Variablen verwenden für Trennzeichen und position (verwenden Sie sql:column zum abrufen der position direkt aus einer Abfrage, die den Wert):

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

Wenn Ihre Zeichenfolge enthalten könnte verbotene Zeichen (vor allem unter &><), Sie immer noch kann es tun auf diese Weise.Verwenden Sie einfach FOR XML PATH auf Ihrem ersten string ersetzen alle Verbotenen Zeichen mit der Montage escape-Sequenz implizit.

Es ist ein sehr spezieller Fall, wenn - darüber hinaus - Ihr Trennzeichen ist das Semikolon.In diesem Fall Ersetze ich das Trennzeichen zuerst '#DLMT#' und ersetzen Sie diese, um die XML-tags zu guter Letzt:

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

UPDATE für SQL-Server 2016+

Mit bedauern die Entwickler vergessen zu Rückkehr die Teil der index mit STRING_SPLIT.Aber, mithilfe von SQL-Server 2016+, es ist OPENJSON.

Die Dokumentation klar erklärt:

Wenn OPENJSON analysiert, die ein JSON-array die Funktion liefert die Indizes der Elemente in der JSON-text als Schlüssel.

Eine Zeichenfolge wie 1,2,3 nichts mehr braucht als Klammern: [1,2,3].
Eine Zeichenfolge der Wörter, wie this is an example werden muss ["this","is","an"," example"].
Dies sind sehr einfache string-Operationen.Probieren Sie es einfach aus:

DECLARE @str VARCHAR(100)='Hello John Smith';

SELECT [value]
FROM OPENJSON('["' + REPLACE(@str,' ','","') + '"]')
WHERE [key]=1 --zero-based!

Hier ist eine benutzerdefinierte Funktion, die es tun.Es wird eine Tabelle zurückgeben, die von der durch Trennzeichen getrennte Werte, habe nicht versucht, alle Szenarien, aber Ihr Beispiel funktioniert gut.


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

Sie würde es so nennen:


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

Edit:Aktualisierte Lösung zu behandeln delimters mit len>1, wie in :


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

Hier Stelle ich einen einfachen Weg Lösung

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 INTO @t(val)
          SELECT  r.value('.','varchar(MAX)') as item
          FROM  @xml.nodes('/t') as records(r)
          RETURN
        END


Führen Sie die Funktion wie diese

  select * from dbo.split('Hello John Smith',' ')

Meiner Meinung nach, Sie Jungs werden machen es viel zu kompliziert.Erstellen Sie einfach eine CLR-UDF-und mit ihm getan werden.

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

Was Sie über die Verwendung string und values() - Anweisung?

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 INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Ergebnis erzielt.

id  item
1   Hello
2   John
3   Smith

Verwende ich die Antwort von frederic aber das hat nicht funktioniert in SQL Server 2005

Ich habe es geändert und ich bin mit select mit union all und es funktioniert

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 INTO @Splited
EXEC(@str)

SELECT * FROM @Splited

Und das Ergebnis ist:

id  item
1   Hello
2   John
3   Smith
4   how
5   are
6   you

Dieses Muster funktioniert gut und man kann verallgemeinern

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

Hinweis FELD, INDEX und TYP.

Lassen Sie uns eine Tabelle mit IDS wie

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

Dann können Sie schreiben

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

Spaltung und Gießen Sie alle Teile.

Wenn Ihre Datenbank-Kompatibilitätsgrad 130 oder höher, dann können Sie die STRING_SPLIT - Funktion zusammen mit OFFSET-FETCH - Klauseln, um die spezifische Element von index.

Um das Element an index N (null basiert), können Sie den folgenden code verwenden

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

Um zu überprüfen die Kompatibilitätsgrad der Datenbank, führen Sie diesen code:

SELECT compatibility_level  
FROM sys.databases WHERE name = 'YourDBName';

Ich war auf der Suche nach der Lösung auf die Netto-und die unten funktioniert für mich.Ref.

Und rufen Sie die Funktion wie folgt :

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 INTO @temptable(Items) VALUES(@slice)       
        SET @String = RIGHT(@String,len(@String) - @idx)       
        IF len(@String) = 0 break       
    END   
    RETURN       
END

Noch ein weiteres n ' th-Teil-string delimeter Funktion:

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

und die Verwendung von:

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

das gibt:

c

Versuchen Sie dies:

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

Testen Sie es, wie diese:

select * from SplitWordList('Hello John Smith')

Das folgende Beispiel verwendet eine rekursive CTE

Update 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 @returns
  SELECT REPLACE(val, ' ','' ) AS val, [level]
  FROM cte
  WHERE val > ''
  RETURN
END

Demo auf SQLFiddle



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

Ich weiß, es ist eine alte Frage ist, aber ich glaube, einigen kann man profitieren Sie von meiner Lösung.

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

Vorteile:

  • Es trennt alle 3 sub-strings deliminator mit ' '.
  • Muss man nicht nutzen, while-Schleife, wie es verringert die Leistung.
  • Keine Notwendigkeit zu Pivot-wie alle daraus resultierenden sub-string angezeigt wird eine Zeile

Einschränkungen:

  • Man muss wissen, die insgesamt keine.Leerzeichen (sub-string).

Hinweis:die Lösung geben kann, sub-string bis zu N.

Zu überwand die Einschränkung, die wir verwenden können die folgenden ref.

Aber wieder die oben Lösung kann nicht verwendet werden in einer Tabelle (Actaully ich war nicht in der Lage, es zu benutzen).

Auch ich hoffe, diese Lösung helfen kann, etwas ein.

Update: Im Falle der Datensätze > 50000 ist es nicht ratsam verwenden LOOPS wie es mindert die Leistung

Fast alle anderen Antworten split-code ersetzen die Zeichenfolge aufgeteilt wird, die unnötig CPU-Zyklen und führt unnötige Speicherzuweisungen.

Ich Decke ein viel besserer Weg, um einen string aufteilen hier: http://www.digitalruby.com/split-string-sql-server/

Hier ist der 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 @SplitStringTable (Value) VALUES (@SplitValue)
    SET @SplitStartPos = @SplitEndPos + 1
    SET @SplitEndPos = CHARINDEX(@SplitDelim, @StringToSplit, @SplitStartPos)
END

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

SET NOCOUNT OFF

-- You can select or join with the values in @SplitStringTable at this point.

Können Sie split eine Zeichenfolge in SQL ohne Funktion:

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

Wenn Sie brauchen, um Unterstützung für beliebige Zeichenfolgen (mit xml-Sonderzeichen)

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

Reine set-basierte Lösung verwenden TVF mit rekursiven CTE.Sie können JOIN und APPLY diese Funktion für jedes dataset.

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

Verwendung:

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

Ergebnis:

value   index
-------------
John    1

Beginnend mit SQL Server 2016 wir string_split

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

SELECT value FROM string_split(@string, ',')

Ein moderner Ansatz mit STRING_SPLIT, erfordert SQL Server 2016 und höher.

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

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

Ergebnis:

RowNr   value
1       Hello
2       John
3       Smith

Jetzt ist es möglich, th N-te element aus der Zeilen-Nummer.

Aaron Bertrand Antwort ist großartig, aber fehlerhaft.Es nicht ordnungsgemäß verarbeiten ein Leerzeichen als Trennzeichen verwendet wird (wie das Beispiel in der ursprünglichen Frage), da die Länge-Funktion-Streifen Leerzeichen.

Das folgende ist der code, mit einer kleinen Anpassung können in den Raum Trennzeichen:

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

Hier ist eine Funktion, werden erfüllen die Frage, ist das Ziel von teilen eines string und der Zugriff auf Element 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

Verwendung:

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

Ergebnis:

John

EINFACHE LÖSUNG FÜR DIE ANALYSE VON VOR-UND NACHNAME

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

In meinem Fall (und in vielen anderen scheint es...), habe ich eine Liste von vor-und Nachnamen getrennt durch ein Leerzeichen.Diese können direkt verwendet werden in einer select-Anweisung, um zu analysieren, vor-und Nachnamen.

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

Ich weiß, das ist spät, aber ich hatte vor kurzem diese Anforderung und kam mit dem folgenden code.Ich habe nicht eine Wahl, die zur Verwendung von Benutzer-definierten Funktion.Hoffe, das hilft.

SELECT 
    SUBSTRING(
                SUBSTRING('Hello John Smith' ,0,CHARINDEX(' ','Hello John Smith',CHARINDEX(' ','Hello John Smith')+1)
                        ),CHARINDEX(' ','Hello John Smith'),LEN('Hello John Smith')
            )

Gut, mir ist nicht alles, das einfacher, aber hier ist der code, den ich verwenden, um die split a comma-delimited input variable in einzelne Werte, und legen Sie es in eine table-variable.Ich bin sicher, Sie könnten ändern Sie diese leicht nach split basierend auf einem Platz und dann eine grundlegende SELECT-Abfrage für die Tabelle variable Holen Sie sich Ihre Ergebnisse.

-- 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 INTO @tblAccountingCycles (AccountingCycle) VALUES (@vchAccountingCycle)
        END
        SET @vchAccountingCycleIDs = RIGHT(@vchAccountingCycleIDs, LEN(@vchAccountingCycleIDs) - @intPosition)
        SET @intPosition = CHARINDEX(',', @vchAccountingCycleIDs, 1)
    END
END

Das Konzept ist so ziemlich das gleiche.Eine andere alternative ist die Nutzung der .NET-Kompatibilität in SQL Server 2005 selbst.Sie können im wesentlichen schreiben Sie selbst eine einfache Methode .NET, die teilen den string und dann freigelegt, die als eine gespeicherte Prozedur/Funktion.

Dies ist etwas, was ich Tat, um eine bestimmte token in einer Zeichenfolge.(Getestet in MSSQL 2008)

Zuerst erstellen Sie die folgenden Funktionen:(gefunden in: hier

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;

und

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

dann können Sie es verwenden, wie:

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

die Rückkehr 1111

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top