So teilen Sie einen durch Kommas getrennten Wert in Spalten auf

Antworten:

12
CREATE FUNCTION [dbo].[fn_split_string_to_column] (
    @string NVARCHAR(MAX),
    @delimiter CHAR(1)
    )
RETURNS @out_put TABLE (
    [column_id] INT IDENTITY(1, 1) NOT NULL,
    [value] NVARCHAR(MAX)
    )
AS
BEGIN
    DECLARE @value NVARCHAR(MAX),
        @pos INT = 0,
        @len INT = 0

    SET @string = CASE 
            WHEN RIGHT(@string, 1) != @delimiter
                THEN @string + @delimiter
            ELSE @string
            END

    WHILE CHARINDEX(@delimiter, @string, @pos + 1) > 0
    BEGIN
        SET @len = CHARINDEX(@delimiter, @string, @pos + 1) - @pos
        SET @value = SUBSTRING(@string, @pos, @len)

        INSERT INTO @out_put ([value])
        SELECT LTRIM(RTRIM(@value)) AS [column]

        SET @pos = CHARINDEX(@delimiter, @string, @pos + @len) + 1
    END

    RETURN
END
Blixter
quelle
3
Dies sollte nicht die akzeptierte Antwort sein ... Ein TVF mit mehreren Anweisungen (sehr schlecht!) Und eine WHILESchleife (noch schlimmer) zusammen werden eine schreckliche Leistung erbringen. Außerdem ist dies eine reine Code- Antwort und löst nicht einmal das Problem. Es gibt viel bessere Ansätze! Für SQL-Server 2016+ suchen Sie nach STRING_SPLIT()(was nicht die Position des Fragments trägt, ein großer Fehler!) Oder dem wirklich schnellen JSONHack. Für ältere Versionen suchen Sie nach dem bekannten XML-Hack (JSON- und XML-Details hier ). Oder suchen Sie nach einem der Mai-iTVFs, die auf rekursiven CTEs basieren.
Shnugo
SQL 2016 und höher:SELECT * FROM STRING_SPLIT('John,Jeremy,Jack',',')
Alaa
Einverstanden mit der gegebenen Lösung. Wenn Sie jedoch SQL Server 2016 sind, können Sie die Funktion string_split verwenden. Sie können diese integrierte Funktion auch hier verwenden. tecloger.com/string-split-function-in-sql-server
Khatri
2
Jeder, der STRING_SPLIT vorschlägt, wie kann diese Funktion die Zeichenfolge in Spalten aufteilen (nicht in Zeilen, wie beabsichtigt)?
Geominded
128

Ihr Zweck kann mit folgender Abfrage gelöst werden:

Select Value  , Substring(FullName, 1,Charindex(',', FullName)-1) as Name,
Substring(FullName, Charindex(',', FullName)+1, LEN(FullName)) as  Surname
from Table1

Es gibt keine vorgefertigte Split-Funktion in SQL Server, daher müssen wir eine benutzerdefinierte Funktion erstellen.

CREATE FUNCTION Split (
      @InputString                  VARCHAR(8000),
      @Delimiter                    VARCHAR(50)
)

RETURNS @Items TABLE (
      Item                          VARCHAR(8000)
)

AS
BEGIN
      IF @Delimiter = ' '
      BEGIN
            SET @Delimiter = ','
            SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
      END

      IF (@Delimiter IS NULL OR @Delimiter = '')
            SET @Delimiter = ','

--INSERT INTO @Items VALUES (@Delimiter) -- Diagnostic
--INSERT INTO @Items VALUES (@InputString) -- Diagnostic

      DECLARE @Item           VARCHAR(8000)
      DECLARE @ItemList       VARCHAR(8000)
      DECLARE @DelimIndex     INT

      SET @ItemList = @InputString
      SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      WHILE (@DelimIndex != 0)
      BEGIN
            SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
            INSERT INTO @Items VALUES (@Item)

            -- Set @ItemList = @ItemList minus one less item
            SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
            SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
      END -- End WHILE

      IF @Item IS NOT NULL -- At least one delimiter was encountered in @InputString
      BEGIN
            SET @Item = @ItemList
            INSERT INTO @Items VALUES (@Item)
      END

      -- No delimiters were encountered in @InputString, so just return @InputString
      ELSE INSERT INTO @Items VALUES (@InputString)

      RETURN

END -- End Function
GO

---- Set Permissions
--GRANT SELECT ON Split TO UserRole1
--GRANT SELECT ON Split TO UserRole2
--GO
Romil Kumar Jain
quelle
1
Schauen Sie sich auch die Zahlentabellenlösung DelimitedSplit8K von Jeff Moden in der Antwort @ughai unten an.
Ruskin
2
SQL 2016 kommt jetzt mit einer Split-Funktion
Tvanharp
SQL 2016 und höher:SELECT * FROM STRING_SPLIT('John,Jeremy,Jack',',')
Alaa
51
;WITH Split_Names (Value,Name, xmlname)
AS
(
    SELECT Value,
    Name,
    CONVERT(XML,'<Names><name>'  
    + REPLACE(Name,',', '</name><name>') + '</name></Names>') AS xmlname
      FROM tblnames
)

 SELECT Value,      
 xmlname.value('/Names[1]/name[1]','varchar(100)') AS Name,    
 xmlname.value('/Names[1]/name[2]','varchar(100)') AS Surname
 FROM Split_Names

und überprüfen Sie auch den Link unten als Referenz

http://jahaines.blogspot.in/2009/06/converting-delimited-string-of-values.html

bvr
quelle
4
Das ist besser .. es ist einfach und kurz.
Kimchi Man
4
Ich liebe diesen Weg wirklich. CHARINDEX und SUBSTRING sind ein Chaos, wenn Sie mehr als 2 Werte teilen müssen (z. B. 1,2,3). Vielen Dank
jotapdiez
2
Großartige Idee. Dreimal so langsam wie das CHARINDEXPlus SUBSTRING, zumindest für mich. :-(
Michel de Ruiter
1
Dies ist GENIUS zum Teilen einer großen Anzahl von Feldern, wenn jedes Feld einen bestimmten Namen benötigt! Die gesamte Abfrage kann problemlos auch mit dynamischem SQL erstellt werden!
Devinbost
4
Tolle Lösung, aber einige Zeichen sind im XML illegal (zum Beispiel '&'), so dass ich jedes Feld in ein CDATA-Tag einschließen musste ...CONVERT(XML,'<Names><name><![CDATA[' + REPLACE(Name,',', ']]></name><name><![CDATA[') + ']]></name></name>') AS xmlname
Tony
44

Die XML-Basisantwort ist einfach und sauber

verweisen Sie dies

DECLARE @S varchar(max),
        @Split char(1),
        @X xml

SELECT @S = 'ab,cd,ef,gh,ij',
       @Split = ','

SELECT @X = CONVERT(xml,' <root> <myvalue>' +
REPLACE(@S,@Split,'</myvalue> <myvalue>') + '</myvalue>   </root> ')

SELECT  T.c.value('.','varchar(20)'),              --retrieve ALL values at once
  T.c.value('(/root/myvalue)[1]','VARCHAR(20)')  , --retrieve index 1 only, which is the 'ab'
  T.c.value('(/root/myvalue)[2]','VARCHAR(20)')
 FROM @X.nodes('/root/myvalue') T(c)
aads
quelle
1
Das ist wirklich cool. Die Array-ähnliche Funktion ist sehr nützlich und ich hatte keine Ahnung davon. Vielen Dank!
Vnge
34

Ich finde das cool

SELECT value,
    PARSENAME(REPLACE(String,',','.'),2) 'Name' ,
    PARSENAME(REPLACE(String,',','.'),1) 'Sur Name'
FROM table WITH (NOLOCK)
Azar
quelle
3
U r Anforderung ist nur für Name und Nachname nur na
Azar
1
Sie müssen sich auch darüber im Klaren sein, dass PARSENAME für Elemente mit mehr als 128 Zeichen NULL zurückgibt.
Luis Cazares
Nett. Funktioniert auch gut für meinen Datensatz!
glass_kites
27

Mit CROSS APPLY

select ParsedData.* 
from MyTable mt
cross apply ( select str = mt.String + ',,' ) f1
cross apply ( select p1 = charindex( ',', str ) ) ap1
cross apply ( select p2 = charindex( ',', str, p1 + 1 ) ) ap2
cross apply ( select Nmame = substring( str, 1, p1-1 )                   
                 , Surname = substring( str, p1+1, p2-p1-1 )
          ) ParsedData
Lavisa
quelle
5
Ich kann mich nicht darum kümmern, warum Sie am Ende der ursprünglichen Zeichenfolge 2 Kommas einfügen müssen, damit dies funktioniert. Warum funktioniert es nicht ohne das "+ ',,'"?
Tomate
@ developer.ejay liegt es daran, dass die Left / SubString-Funktionen keinen 0-Wert annehmen können?
Waller
Toll! Sie können einfach 2 Zeilen für jede gewünschte zusätzliche Spalte kopieren / einfügen - dann erhöhen Sie einfach die Zahlen, z. B.: Wählen Sie ParsedData. * Aus MyTable mt cross apply (wählen Sie str = mt.String + ',,') f1 cross apply (wählen Sie p1 = Zeichenindex (',', str)) ap1 Kreuz anwenden (Auswahl p2 = Zeichenindex (',', str, p1 + 1)) ap2 Kreuz anwenden (Auswahl p3 = Zeichenindex (',', str, p2 + 1)) ap3 Kreuz anwenden (wählen Sie FName = Teilzeichenfolge (str, 1, p1-1), LName = Teilzeichenfolge (str, p1 + 1, p2-p1-1), Alter = Teilzeichenfolge (str, p2 + 1, p3-p2-1) )) ParsedData
Mike
23

Es gibt mehrere Möglichkeiten, dies zu lösen, und es wurden bereits viele verschiedene Möglichkeiten vorgeschlagen. Am einfachsten wäre es, LEFT/ SUBSTRINGund andere Zeichenfolgenfunktionen zu verwenden, um das gewünschte Ergebnis zu erzielen.

Beispieldaten

DECLARE @tbl1 TABLE (Value INT,String VARCHAR(MAX))

INSERT INTO @tbl1 VALUES(1,'Cleo, Smith');
INSERT INTO @tbl1 VALUES(2,'John, Mathew');

Verwenden von String-Funktionen wie LEFT

SELECT
    Value,
    LEFT(String,CHARINDEX(',',String)-1) as Fname,
    LTRIM(RIGHT(String,LEN(String) - CHARINDEX(',',String) )) AS Lname
FROM @tbl1

Dieser Ansatz schlägt fehl, wenn ein String mehr als 2 Elemente enthält. In einem solchen Szenario können wir einen Splitter verwenden und dann PIVOTdie Zeichenfolge verwenden oder in eine konvertieren XMLund verwenden .nodes, um Zeichenfolgenelemente abzurufen. XMLDie basierte Lösung wurde von aads und bvr in ihrer Lösung detailliert beschrieben.

Die Antworten auf diese Frage, die Splitter verwenden, verwenden alle, WHILEdie für das Teilen ineffizient sind. Überprüfen Sie diesen Leistungsvergleich . Einer der besten Splitter ist DelimitedSplit8KJeff Moden. Sie können mehr darüber lesen Sie hier

Splitter mit PIVOT

DECLARE @tbl1 TABLE (Value INT,String VARCHAR(MAX))

INSERT INTO @tbl1 VALUES(1,'Cleo, Smith');
INSERT INTO @tbl1 VALUES(2,'John, Mathew');


SELECT t3.Value,[1] as Fname,[2] as Lname
FROM @tbl1 as t1
CROSS APPLY [dbo].[DelimitedSplit8K](String,',') as t2
PIVOT(MAX(Item) FOR ItemNumber IN ([1],[2])) as t3

Ausgabe

Value   Fname   Lname
1   Cleo    Smith
2   John    Mathew

DelimitedSplit8K von Jeff Moden

CREATE FUNCTION [dbo].[DelimitedSplit8K]
/**********************************************************************************************************************
 Purpose:
 Split a given string at a given delimiter and return a list of the split elements (items).

 Notes:
 1.  Leading a trailing delimiters are treated as if an empty string element were present.
 2.  Consecutive delimiters are treated as if an empty string element were present between them.
 3.  Except when spaces are used as a delimiter, all spaces present in each element are preserved.

 Returns:
 iTVF containing the following:
 ItemNumber = Element position of Item as a BIGINT (not converted to INT to eliminate a CAST)
 Item       = Element value as a VARCHAR(8000)

 Statistics on this function may be found at the following URL:
 http://www.sqlservercentral.com/Forums/Topic1101315-203-4.aspx

 CROSS APPLY Usage Examples and Tests:
--=====================================================================================================================
-- TEST 1:
-- This tests for various possible conditions in a string using a comma as the delimiter.  The expected results are
-- laid out in the comments
--=====================================================================================================================
--===== Conditionally drop the test tables to make reruns easier for testing.
     -- (this is NOT a part of the solution)
     IF OBJECT_ID('tempdb..#JBMTest') IS NOT NULL DROP TABLE #JBMTest
;
--===== Create and populate a test table on the fly (this is NOT a part of the solution).
     -- In the following comments, "b" is a blank and "E" is an element in the left to right order.
     -- Double Quotes are used to encapsulate the output of "Item" so that you can see that all blanks
     -- are preserved no matter where they may appear.
 SELECT *
   INTO #JBMTest
   FROM (                                               --# & type of Return Row(s)
         SELECT  0, NULL                      UNION ALL --1 NULL
         SELECT  1, SPACE(0)                  UNION ALL --1 b (Empty String)
         SELECT  2, SPACE(1)                  UNION ALL --1 b (1 space)
         SELECT  3, SPACE(5)                  UNION ALL --1 b (5 spaces)
         SELECT  4, ','                       UNION ALL --2 b b (both are empty strings)
         SELECT  5, '55555'                   UNION ALL --1 E
         SELECT  6, ',55555'                  UNION ALL --2 b E
         SELECT  7, ',55555,'                 UNION ALL --3 b E b
         SELECT  8, '55555,'                  UNION ALL --2 b B
         SELECT  9, '55555,1'                 UNION ALL --2 E E
         SELECT 10, '1,55555'                 UNION ALL --2 E E
         SELECT 11, '55555,4444,333,22,1'     UNION ALL --5 E E E E E 
         SELECT 12, '55555,4444,,333,22,1'    UNION ALL --6 E E b E E E
         SELECT 13, ',55555,4444,,333,22,1,'  UNION ALL --8 b E E b E E E b
         SELECT 14, ',55555,4444,,,333,22,1,' UNION ALL --9 b E E b b E E E b
         SELECT 15, ' 4444,55555 '            UNION ALL --2 E (w/Leading Space) E (w/Trailing Space)
         SELECT 16, 'This,is,a,test.'                   --E E E E
        ) d (SomeID, SomeValue)
;
--===== Split the CSV column for the whole table using CROSS APPLY (this is the solution)
 SELECT test.SomeID, test.SomeValue, split.ItemNumber, Item = QUOTENAME(split.Item,'"')
   FROM #JBMTest test
  CROSS APPLY dbo.DelimitedSplit8K(test.SomeValue,',') split
;
--=====================================================================================================================
-- TEST 2:
-- This tests for various "alpha" splits and COLLATION using all ASCII characters from 0 to 255 as a delimiter against
-- a given string.  Note that not all of the delimiters will be visible and some will show up as tiny squares because
-- they are "control" characters.  More specifically, this test will show you what happens to various non-accented 
-- letters for your given collation depending on the delimiter you chose.
--=====================================================================================================================
WITH 
cteBuildAllCharacters (String,Delimiter) AS 
(
 SELECT TOP 256 
        'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789',
        CHAR(ROW_NUMBER() OVER (ORDER BY (SELECT NULL))-1)
   FROM master.sys.all_columns
)
 SELECT ASCII_Value = ASCII(c.Delimiter), c.Delimiter, split.ItemNumber, Item = QUOTENAME(split.Item,'"')
   FROM cteBuildAllCharacters c
  CROSS APPLY dbo.DelimitedSplit8K(c.String,c.Delimiter) split
  ORDER BY ASCII_Value, split.ItemNumber
;
-----------------------------------------------------------------------------------------------------------------------
 Other Notes:
 1. Optimized for VARCHAR(8000) or less.  No testing or error reporting for truncation at 8000 characters is done.
 2. Optimized for single character delimiter.  Multi-character delimiters should be resolvedexternally from this 
    function.
 3. Optimized for use with CROSS APPLY.
 4. Does not "trim" elements just in case leading or trailing blanks are intended.
 5. If you don't know how a Tally table can be used to replace loops, please see the following...
    http://www.sqlservercentral.com/articles/T-SQL/62867/
 6. Changing this function to use NVARCHAR(MAX) will cause it to run twice as slow.  It's just the nature of 
    VARCHAR(MAX) whether it fits in-row or not.
 7. Multi-machine testing for the method of using UNPIVOT instead of 10 SELECT/UNION ALLs shows that the UNPIVOT method
    is quite machine dependent and can slow things down quite a bit.
-----------------------------------------------------------------------------------------------------------------------
 Credits:
 This code is the product of many people's efforts including but not limited to the following:
 cteTally concept originally by Iztek Ben Gan and "decimalized" by Lynn Pettis (and others) for a bit of extra speed
 and finally redacted by Jeff Moden for a different slant on readability and compactness. Hat's off to Paul White for
 his simple explanations of CROSS APPLY and for his detailed testing efforts. Last but not least, thanks to
 Ron "BitBucket" McCullough and Wayne Sheffield for their extreme performance testing across multiple machines and
 versions of SQL Server.  The latest improvement brought an additional 15-20% improvement over Rev 05.  Special thanks
 to "Nadrek" and "peter-757102" (aka Peter de Heer) for bringing such improvements to light.  Nadrek's original
 improvement brought about a 10% performance gain and Peter followed that up with the content of Rev 07.  

 I also thank whoever wrote the first article I ever saw on "numbers tables" which is located at the following URL
 and to Adam Machanic for leading me to it many years ago.
 http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-numbers-table.html
-----------------------------------------------------------------------------------------------------------------------
 Revision History:
 Rev 00 - 20 Jan 2010 - Concept for inline cteTally: Lynn Pettis and others.
                        Redaction/Implementation: Jeff Moden 
        - Base 10 redaction and reduction for CTE.  (Total rewrite)

 Rev 01 - 13 Mar 2010 - Jeff Moden
        - Removed one additional concatenation and one subtraction from the SUBSTRING in the SELECT List for that tiny
          bit of extra speed.

 Rev 02 - 14 Apr 2010 - Jeff Moden
        - No code changes.  Added CROSS APPLY usage example to the header, some additional credits, and extra 
          documentation.

 Rev 03 - 18 Apr 2010 - Jeff Moden
        - No code changes.  Added notes 7, 8, and 9 about certain "optimizations" that don't actually work for this
          type of function.

 Rev 04 - 29 Jun 2010 - Jeff Moden
        - Added WITH SCHEMABINDING thanks to a note by Paul White.  This prevents an unnecessary "Table Spool" when the
          function is used in an UPDATE statement even though the function makes no external references.

 Rev 05 - 02 Apr 2011 - Jeff Moden
        - Rewritten for extreme performance improvement especially for larger strings approaching the 8K boundary and
          for strings that have wider elements.  The redaction of this code involved removing ALL concatenation of 
          delimiters, optimization of the maximum "N" value by using TOP instead of including it in the WHERE clause,
          and the reduction of all previous calculations (thanks to the switch to a "zero based" cteTally) to just one 
          instance of one add and one instance of a subtract. The length calculation for the final element (not 
          followed by a delimiter) in the string to be split has been greatly simplified by using the ISNULL/NULLIF 
          combination to determine when the CHARINDEX returned a 0 which indicates there are no more delimiters to be
          had or to start with. Depending on the width of the elements, this code is between 4 and 8 times faster on a
          single CPU box than the original code especially near the 8K boundary.
        - Modified comments to include more sanity checks on the usage example, etc.
        - Removed "other" notes 8 and 9 as they were no longer applicable.

 Rev 06 - 12 Apr 2011 - Jeff Moden
        - Based on a suggestion by Ron "Bitbucket" McCullough, additional test rows were added to the sample code and
          the code was changed to encapsulate the output in pipes so that spaces and empty strings could be perceived 
          in the output.  The first "Notes" section was added.  Finally, an extra test was added to the comments above.

 Rev 07 - 06 May 2011 - Peter de Heer, a further 15-20% performance enhancement has been discovered and incorporated 
          into this code which also eliminated the need for a "zero" position in the cteTally table. 
**********************************************************************************************************************/
--===== Define I/O parameters
        (@pString VARCHAR(8000), @pDelimiter CHAR(1))
RETURNS TABLE WITH SCHEMABINDING AS
 RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 0 up to 10,000...
     -- enough to cover NVARCHAR(4000)
  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
                ),                          --10E+1 or 10 rows
       E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
       E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
 cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
                     -- for both a performance gain and prevention of accidental "overruns"
                 SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
                ),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
                 SELECT 1 UNION ALL
                 SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
                ),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
                 SELECT s.N1,
                        ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
                   FROM cteStart s
                )
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
 SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
        Item       = SUBSTRING(@pString, l.N1, l.L1)
   FROM cteLen l
;

GO
ughai
quelle
15

Versuchen Sie dies (ändern Sie die Instanzen von '' in '' oder einen beliebigen Begrenzer, den Sie verwenden möchten).

CREATE FUNCTION dbo.Wordparser
(
  @multiwordstring VARCHAR(255),
  @wordnumber      NUMERIC
)
returns VARCHAR(255)
AS
  BEGIN
      DECLARE @remainingstring VARCHAR(255)
      SET @remainingstring=@multiwordstring

      DECLARE @numberofwords NUMERIC
      SET @numberofwords=(LEN(@remainingstring) - LEN(REPLACE(@remainingstring, ' ', '')) + 1)

      DECLARE @word VARCHAR(50)
      DECLARE @parsedwords TABLE
      (
         line NUMERIC IDENTITY(1, 1),
         word VARCHAR(255)
      )

      WHILE @numberofwords > 1
        BEGIN
            SET @word=LEFT(@remainingstring, CHARINDEX(' ', @remainingstring) - 1)

            INSERT INTO @parsedwords(word)
            SELECT @word

            SET @remainingstring= REPLACE(@remainingstring, Concat(@word, ' '), '')
            SET @numberofwords=(LEN(@remainingstring) - LEN(REPLACE(@remainingstring, ' ', '')) + 1)

            IF @numberofwords = 1
              BREAK

            ELSE
              CONTINUE
        END

      IF @numberofwords = 1
        SELECT @word = @remainingstring
      INSERT INTO @parsedwords(word)
      SELECT @word

      RETURN
        (SELECT word
         FROM   @parsedwords
         WHERE  line = @wordnumber)

  END

Anwendungsbeispiel:

SELECT dbo.Wordparser(COLUMN, 1),
       dbo.Wordparser(COLUMN, 2),
       dbo.Wordparser(COLUMN, 3)
FROM   TABLE
user7347410
quelle
Bei mir fehlgeschlagen, wenn identische Werte in derselben Zeile.
Pete Alvin
14

Mit SQL Server 2016 können wir string_split verwenden, um dies zu erreichen:

create table commasep (
 id int identity(1,1)
 ,string nvarchar(100) )

insert into commasep (string) values ('John, Adam'), ('test1,test2,test3')

select id, [value] as String from commasep 
 cross apply string_split(string,',')
Kannan Kandasamy
quelle
Ich benutze SQL Server 2016, aber es gibt einen FehlerInvalid object name 'string_split'
ibiza
2
Können Sie die Kompatibilitätsstufe Ihrer Datenbank überprüfen? Es muss 130 sein, was SQL Server 2016 ist. Sie können diese Abfrage verwenden, wählen Sie * aus sys.databases
Kannan Kandasamy
Richtig, ich sehe 120, es muss also nur der Client (Microsoft SQL Server Management Studio) sein, der 2016 ist, und nicht der Datenbankserver an sich, denn wenn ich zu Hilfe -> Info gehe, sehe ich SQL Server 2016 Management Studio v13.0.15000. 23. Vielen Dank
Ibiza
Es kann vorkommen, dass der Level von den Datenbankentwicklern auf einen niedrigeren Wert eingestellt wird, um die Datenbank kompatibel zu halten, selbst wenn die tatsächlich installierte Version höher ist. Verwenden Sie diese Option, um den Pegel so hoch wie erforderlich einzustellen, solange die Datenbank dies unterstützt:DECLARE @cl TINYINT; SELECT @cl = compatibility_level FROM [sys].[databases] WHERE name = 'mydb'; IF @cl < 130 BEGIN ALTER DATABASE myDb SET COMPATIBILITY_LEVEL = 130 END;
Jörg Krause
Dies ist nutzlos, es sei denn, Sie schwenken es von Zeilen zu Spalten zurück.
Guy Manova
12

Ich denke, PARSENAME ist die nette Funktion für dieses Beispiel, wie in diesem Artikel beschrieben: http://www.sqlshack.com/parsing-and-rotating-delimited-data-in-sql-server-2012/

Die Funktion PARSENAME ist logisch ausgelegt, um vierteilige Objektnamen zu analysieren. Das Schöne an PARSENAME ist, dass es nicht nur auf das Parsen von vierteiligen SQL Server-Objektnamen beschränkt ist, sondern auch auf Funktions- oder Zeichenfolgendaten, die durch Punkte begrenzt sind.

Der erste Parameter ist das zu analysierende Objekt und der zweite ist der ganzzahlige Wert des zurückzugebenden Objektstücks. Der Artikel befasst sich mit dem Parsen und Drehen von begrenzten Daten - Firmen-Telefonnummern, kann jedoch auch zum Parsen von Vor- / Nachnamen verwendet werden.

Beispiel:

USE COMPANY;
SELECT PARSENAME('Whatever.you.want.parsed',3) AS 'ReturnValue';

In diesem Artikel wird auch die Verwendung eines Common Table Expression (CTE) mit dem Namen 'replaceChars' beschrieben, um PARSENAME für die durch Trennzeichen ersetzten Werte auszuführen. Ein CTE ist nützlich, um eine temporäre Ansicht oder Ergebnismenge zurückzugeben.

Danach wurde die UNPIVOT-Funktion verwendet, um einige Spalten in Zeilen zu konvertieren. Die Funktionen SUBSTRING und CHARINDEX wurden zum Bereinigen der Inkonsistenzen in den Daten verwendet, und die LAG-Funktion (neu für SQL Server 2012) wurde am Ende verwendet, da sie das Referenzieren früherer Datensätze ermöglicht.

JasonP
quelle
11
SELECT id,
       Substring(NAME, 0, Charindex(',', NAME))             AS firstname,
       Substring(NAME, Charindex(',', NAME), Len(NAME) + 1) AS lastname
FROM   spilt  
anonym
quelle
6
Es wäre nützlich, wenn Sie Ihre Antwort erweitern und auch die Code-Formatierungswerkzeuge verwenden könnten.
Politank-Z
Schließen, dies schließt das Komma im Nachnamen ein. Habe die +1 an der falschen Stelle. Sollte Teilzeichenfolge (NAME, Charindex (',', NAME) +1, Len (NAME)) als Nachname sein
LarryBud
10

Wir können eine Funktion wie diese erstellen

CREATE Function [dbo].[fn_CSVToTable] 
(
    @CSVList Varchar(max)
)
RETURNS @Table TABLE (ColumnData VARCHAR(100))
AS
BEGIN
    IF RIGHT(@CSVList, 1) <> ','
    SELECT @CSVList = @CSVList + ','

    DECLARE @Pos    BIGINT,
            @OldPos BIGINT
    SELECT  @Pos    = 1,
            @OldPos = 1

    WHILE   @Pos < LEN(@CSVList)
        BEGIN
            SELECT  @Pos = CHARINDEX(',', @CSVList, @OldPos)
            INSERT INTO @Table
            SELECT  LTRIM(RTRIM(SUBSTRING(@CSVList, @OldPos, @Pos - @OldPos))) Col001

            SELECT  @OldPos = @Pos + 1
        END

    RETURN
END

Anschließend können wir die CSV-Werte mithilfe einer SELECT-Anweisung in unsere jeweiligen Spalten aufteilen

Himansz
quelle
8

Ich denke, folgende Funktion wird für Sie funktionieren:

Sie müssen zuerst eine Funktion in SQL erstellen. So was

CREATE FUNCTION [dbo].[fn_split](
@str VARCHAR(MAX),
@delimiter CHAR(1)
)
RETURNS @returnTable TABLE (idx INT PRIMARY KEY IDENTITY, item VARCHAR(8000))
AS
BEGIN
DECLARE @pos INT
SELECT @str = @str + @delimiter
WHILE LEN(@str) > 0 
    BEGIN
        SELECT @pos = CHARINDEX(@delimiter,@str)
        IF @pos = 1
            INSERT @returnTable (item)
                VALUES (NULL)
        ELSE
            INSERT @returnTable (item)
                VALUES (SUBSTRING(@str, 1, @pos-1))
        SELECT @str = SUBSTRING(@str, @pos+1, LEN(@str)-@pos)       
    END
RETURN
END

Sie können diese Funktion folgendermaßen aufrufen:

select * from fn_split('1,24,5',',')

Implementierung:

Declare @test TABLE (
ID VARCHAR(200),
Data VARCHAR(200)
)

insert into @test 
(ID, Data)
Values
('1','Cleo,Smith')


insert into @test 
(ID, Data)
Values
('2','Paul,Grim')

select ID,
(select item from fn_split(Data,',') where idx in (1)) as Name ,
(select item from fn_split(Data,',') where idx in (2)) as Surname
 from @test

Ergebnis wird dies gefallen:

Geben Sie hier die Bildbeschreibung ein

Muhammad Awais
quelle
Die Verwendung von Schleifen zum Teilen von Zeichenfolgen ist schrecklich ineffizient. Hier sind einige bessere Optionen für diese Split-Funktion. sqlperformance.com/2012/07/t-sql-queries/split-strings
Sean Lange
8

Sie können eine Tabellenfunktion verwenden STRING_SPLIT, die nur unter der Kompatibilitätsstufe 130 verfügbar ist. Wenn Ihre Datenbankkompatibilitätsstufe unter 130 liegt, kann SQL Server die STRING_SPLITFunktion nicht finden und ausführen . Sie können eine Kompatibilitätsstufe der Datenbank mit dem folgenden Befehl ändern:

ALTER DATABASE DatabaseName SET COMPATIBILITY_LEVEL = 130

Syntax

SELECT * FROM STRING_SPLIT ( string, separator )

siehe Dokumentation hier

Bwanamaina
quelle
Nett. Es gilt jedoch nicht für SQL Server unter 2016
Lokesh
Richtig, in meiner Antwort habe ich angegeben, dass es nur in Kompatibilitätsstufe 130 und höher verfügbar sein wird.
Bwanamaina
1
STRING_SPLIT wurde jedoch in mehrere Zeilen aufgeteilt, nicht in mehrere Spalten für jede Aufteilung. Das OP fragte nach einer Aufteilung in mehrere Spalten, oder?
Geominded
7

Verwenden Sie die Funktion Parsename ()

with cte as(
    select 'Aria,Karimi' as FullName
    Union
    select 'Joe,Karimi' as FullName
    Union
    select 'Bab,Karimi' as FullName
)

SELECT PARSENAME(REPLACE(FullName,',','.'),2) as Name, 
       PARSENAME(REPLACE(FullName,',','.'),1) as Family
    FROM cte

Ergebnis

Name    Family
-----   ------
Aria    Karimi
Bab     Karimi
Joe     Karimi
Mohammad Karimi
quelle
6

Versuche dies:

declare @csv varchar(100) ='aaa,bb,csda,daass';
set @csv = @csv+',';

with cte as
(
    select SUBSTRING(@csv,1,charindex(',',@csv,1)-1) as val, SUBSTRING(@csv,charindex(',',@csv,1)+1,len(@csv)) as rem 
    UNION ALL
    select SUBSTRING(a.rem,1,charindex(',',a.rem,1)-1)as val, SUBSTRING(a.rem,charindex(',',a.rem,1)+1,len(A.rem)) 
    from cte a where LEN(a.rem)>=1
    ) select val from cte
Rangani
quelle
Arbeite wie ein Zauber!
Yu Yang Jian
5

Ich bin auf ein ähnliches Problem gestoßen, aber auf ein komplexes. Da dies der erste Thread ist, den ich zu diesem Problem gefunden habe, habe ich beschlossen, meinen Befund zu veröffentlichen. Ich weiß, dass es eine komplexe Lösung für ein einfaches Problem ist, aber ich hoffe, dass ich anderen Menschen helfen kann, die zu diesem Thread gehen und nach einer komplexeren Lösung suchen. Ich musste eine Zeichenfolge mit 5 Zahlen (Spaltenname: LevelsFeed) teilen und jede Zahl in einer separaten Spalte anzeigen. Zum Beispiel: 8,1,2,2,2 sollte wie folgt angezeigt werden:

1  2  3  4  5
-------------
8  1  2  2  2

Lösung 1: Verwenden von XML-Funktionen: Diese Lösung ist mit Abstand die langsamste Lösung

SELECT Distinct FeedbackID, 
, S.a.value('(/H/r)[1]', 'INT') AS level1
, S.a.value('(/H/r)[2]', 'INT') AS level2
, S.a.value('(/H/r)[3]', 'INT') AS level3
, S.a.value('(/H/r)[4]', 'INT') AS level4
, S.a.value('(/H/r)[5]', 'INT') AS level5
FROM (            
    SELECT *,CAST (N'<H><r>' + REPLACE(levelsFeed, ',', '</r><r>')  + '</r> </H>' AS XML) AS [vals]
    FROM Feedbacks 
)  as d
CROSS APPLY d.[vals].nodes('/H/r') S(a)

Lösung 2: Verwenden der Split-Funktion und des Pivots. (Die Split-Funktion teilt eine Zeichenfolge in Zeilen mit dem Spaltennamen Data auf.)

SELECT FeedbackID, [1],[2],[3],[4],[5]
FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY feedbackID ORDER BY (SELECT  null)) as rn 
FROM (
    SELECT FeedbackID, levelsFeed
    FROM Feedbacks 
) as a
CROSS APPLY dbo.Split(levelsFeed, ',')
) as SourceTable
PIVOT
(
    MAX(data)
    FOR rn IN ([1],[2],[3],[4],[5])
)as pivotTable

Lösung 3: Verwenden von Funktionen zur Manipulation von Zeichenfolgen - am schnellsten mit geringem Abstand gegenüber Lösung 2

SELECT FeedbackID,
SUBSTRING(levelsFeed,0,CHARINDEX(',',levelsFeed)) AS level1,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),4) AS level2,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),3) AS level3,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),2) AS level4,
PARSENAME(REPLACE(SUBSTRING(levelsFeed,CHARINDEX(',',levelsFeed)+1,LEN(levelsFeed)),',','.'),1) AS level5
FROM Feedbacks

Da die EbenenFeed 5 Zeichenfolgenwerte enthält, musste ich die Teilzeichenfolgenfunktion für die erste Zeichenfolge verwenden.

Ich hoffe, dass meine Lösung anderen helfen wird, die zu diesem Thread gekommen sind und nach einer komplexeren Methode zur Aufteilung in Spalten suchen

Yossi
quelle
5

Instring-Funktion verwenden :)

select Value, 
       substring(String,1,instr(String," ") -1) Fname,  
       substring(String,instr(String,",") +1) Sname 
from tablename;

Verwendete zwei Funktionen:
1. substring(string, position, length) ==> gibt den String von Position zu Länge zurück
2. instr(string,pattern)==> gibt die Position des Musters zurück.

Wenn wir im Teilstring kein Längenargument angeben, wird es bis zum Ende des Strings zurückgegeben

Holzfäller
quelle
1
Sie sind sich nicht sicher, welchen SQL-Dialekt Sie verwenden, aber in SQL Server müssten wir so etwas wie substring(@str, 1, charindex(@sep, @str) - 1)gefolgt von verwenden substring(@str, charindex(@sep, @str) + 1, len(@str)).
Peter B
5

Diese Funktion ist am schnellsten:

CREATE FUNCTION dbo.F_ExtractSubString
(
  @String VARCHAR(MAX),
  @NroSubString INT,
  @Separator VARCHAR(5)
)
RETURNS VARCHAR(MAX) AS
BEGIN
    DECLARE @St INT = 0, @End INT = 0, @Ret VARCHAR(MAX)
    SET @String = @String + @Separator
    WHILE CHARINDEX(@Separator, @String, @End + 1) > 0 AND @NroSubString > 0
    BEGIN
        SET @St = @End + 1
        SET @End = CHARINDEX(@Separator, @String, @End + 1)
        SET @NroSubString = @NroSubString - 1
    END
    IF @NroSubString > 0
        SET @Ret = ''
    ELSE
        SET @Ret = SUBSTRING(@String, @St, @End - @St)
    RETURN @Ret
END
GO

Anwendungsbeispiel:

SELECT dbo.F_ExtractSubString(COLUMN, 1, ', '),
       dbo.F_ExtractSubString(COLUMN, 2, ', '),
       dbo.F_ExtractSubString(COLUMN, 3, ', ')
FROM   TABLE
Mariano Sedano
quelle
3
Vielen Dank für dieses Code-Snippet, das möglicherweise nur begrenzte, sofortige Hilfe bietet. Eine richtige Erklärung würde ihren langfristigen Wert erheblich verbessern, indem sie zeigt, warum dies eine gute Lösung für das Problem ist, und es für zukünftige Leser mit anderen, ähnlichen Fragen nützlicher machen. Bitte bearbeiten Sie Ihre Antwort, um eine Erklärung hinzuzufügen, einschließlich der von Ihnen getroffenen Annahmen.
Toby Speight
4

Das hat bei mir funktioniert

CREATE FUNCTION [dbo].[SplitString](
    @delimited NVARCHAR(MAX),
    @delimiter NVARCHAR(100)
) RETURNS @t TABLE ( 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
Krishna
quelle
Wissen Sie, wie man mit XML-Sonderzeichen umgeht?
Zach Smith
3

mein Tisch:

Value  ColOne
--------------------
1      Cleo, Smith

Folgendes sollte funktionieren, wenn nicht zu viele Spalten vorhanden sind

ALTER TABLE mytable ADD ColTwo nvarchar(256);
UPDATE mytable SET ColTwo = LEFT(ColOne, Charindex(',', ColOne) - 1);
--'Cleo' = LEFT('Cleo, Smith', Charindex(',', 'Cleo, Smith') - 1)
UPDATE mytable SET ColTwo = REPLACE(ColOne, ColTwo + ',', '');
--' Smith' = REPLACE('Cleo, Smith', 'Cleo' + ',')
UPDATE mytable SET ColOne = REPLACE(ColOne, ',' + ColTwo, ''), ColTwo = LTRIM(ColTwo);
--'Cleo' = REPLACE('Cleo, Smith', ',' + ' Smith', '') 

Ergebnis:

Value  ColOne ColTwo
--------------------
1      Cleo   Smith
kolunar
quelle
3

Es ist so einfach, dass Sie es mit der folgenden Abfrage beantworten können:

DECLARE @str NVARCHAR(MAX)='ControlID_05436b78-04ba-9667-fa01-9ff8c1b7c235,3'
SELECT LEFT(@str, CHARINDEX(',',@str)-1),RIGHT(@str,LEN(@str)-(CHARINDEX(',',@str)))
Mehdi Najafian
quelle
3
DECLARE @INPUT VARCHAR (MAX)='N,A,R,E,N,D,R,A'
DECLARE @ELIMINATE_CHAR CHAR (1)=','
DECLARE @L_START INT=1
DECLARE @L_END INT=(SELECT LEN (@INPUT))
DECLARE @OUTPUT CHAR (1)

WHILE @L_START <=@L_END
BEGIN
    SET @OUTPUT=(SUBSTRING (@INPUT,@L_START,1))
    IF @OUTPUT!=@ELIMINATE_CHAR
    BEGIN
        PRINT @OUTPUT
    END
    SET @L_START=@L_START+1
END
Narendra Gudapati
quelle
Ich habe Ihren Code verwendet, es ist einfach, aber es gibt Rechtschreibfehler in ELIMINATE_CHAT. Es sollte ELIMINATE_CHAR sein und START am Ende des Skripts sollte L_START sein. Danke.
Wessam El Mahdy
3

Möglicherweise finden Sie die Lösung in SQL User Defined Function zum Parsen einer durch Trennzeichen getrennten Zeichenfolge hilfreich (aus The Code Project ).

Dies ist der Codeteil dieser Seite:

CREATE FUNCTION [fn_ParseText2Table]
  (@p_SourceText VARCHAR(MAX)
  ,@p_Delimeter VARCHAR(100)=',' --default to comma delimited.
  )
 RETURNS @retTable
  TABLE([Position] INT IDENTITY(1,1)
   ,[Int_Value] INT
   ,[Num_Value] NUMERIC(18,3)
   ,[Txt_Value] VARCHAR(MAX)
   ,[Date_value] DATETIME
   )
AS
/*
********************************************************************************
Purpose: Parse values from a delimited string
  & return the result as an indexed table
Copyright 1996, 1997, 2000, 2003 Clayton Groom (<A href="mailto:[email protected]">[email protected]</A>)
Posted to the public domain Aug, 2004
2003-06-17 Rewritten as SQL 2000 function.
 Reworked to allow for delimiters > 1 character in length
 and to convert Text values to numbers
2016-04-05 Added logic for date values based on "new" ISDATE() function, Updated to use XML approach, which is more efficient.
********************************************************************************
*/


BEGIN
 DECLARE @w_xml xml;
 SET @w_xml = N'<root><i>' + replace(@p_SourceText, @p_Delimeter,'</i><i>') + '</i></root>';


 INSERT INTO @retTable
     ([Int_Value]
    , [Num_Value]
    , [Txt_Value]
    , [Date_value]
     )
     SELECT CASE
       WHEN ISNUMERIC([i].value('.', 'VARCHAR(MAX)')) = 1
       THEN CAST(CAST([i].value('.', 'VARCHAR(MAX)') AS NUMERIC) AS INT)
      END AS [Int_Value]
    , CASE
       WHEN ISNUMERIC([i].value('.', 'VARCHAR(MAX)')) = 1
       THEN CAST([i].value('.', 'VARCHAR(MAX)') AS NUMERIC(18, 3))
      END AS [Num_Value]
    , [i].value('.', 'VARCHAR(MAX)') AS [txt_Value]
    , CASE
       WHEN ISDATE([i].value('.', 'VARCHAR(MAX)')) = 1
       THEN CAST([i].value('.', 'VARCHAR(MAX)') AS DATETIME)
      END AS [Num_Value]
     FROM @w_xml.nodes('//root/i') AS [Items]([i]);
 RETURN;
END;
GO
Michael Schnerring
quelle
11
Gibt es eine Möglichkeit, die Lösung hier zusammenzufassen, um sicherzustellen, dass die Antwort nicht veraltet ist, falls der Link jemals stirbt?
Adam Lear
3
ALTER function get_occurance_index(@delimiter varchar(1),@occurence int,@String varchar(100))
returns int
AS Begin
--Declare @delimiter varchar(1)=',',@occurence int=2,@String varchar(100)='a,b,c'
Declare @result int
 ;with T as (
    select 1 Rno,0 as row, charindex(@delimiter, @String) pos,@String st
    union all
    select Rno+1,pos + 1, charindex(@delimiter, @String, pos + 1), @String
    from T
    where pos > 0
)
select  @result=pos 
from T 
where pos > 0   and rno = @occurence 
return isnull(@result,0)
ENd


declare @data as table (data varchar(100))
insert into @data values('1,2,3') 
insert into @data values('aaa,bbbbb,cccc') 
select top  3 Substring (data,0,dbo.get_occurance_index( ',',1,data)) ,--First Record always starts with 0
Substring (data,dbo.get_occurance_index( ',',1,data)+1,dbo.get_occurance_index( ',',2,data)-dbo.get_occurance_index( ',',1,data)-1) ,
Substring (data,dbo.get_occurance_index( ',',2,data)+1,len(data)) , -- Last record cant be more than len of actual data
data 
From @data 
Vignesh
quelle
2

Ich fand heraus, dass die Verwendung von PARSENAME wie oben dazu führte, dass ein Name mit einem Punkt auf Null gesetzt wurde.

Wenn der Name also eine Initiale oder einen Titel gefolgt von einem Punkt enthält, wird NULL zurückgegeben.

Ich fand das funktionierte für mich:

SELECT 
REPLACE(SUBSTRING(FullName, 1,CHARINDEX(',', FullName)), ',','') as Name,
REPLACE(SUBSTRING(FullName, CHARINDEX(',', FullName), LEN(FullName)), ',', '') as Surname
FROM Table1
RoadRunner
quelle
2
select distinct modelFileId,F4.*
from contract
cross apply (select XmlList=convert(xml, '<x>'+replace(modelFileId,';','</x><x>')+'</x>').query('.')) F2
cross apply (select mfid1=XmlNode.value('/x[1]','varchar(512)')
,mfid2=XmlNode.value('/x[2]','varchar(512)')
,mfid3=XmlNode.value('/x[3]','varchar(512)')
,mfid4=XmlNode.value('/x[4]','varchar(512)') from XmlList.nodes('x') F3(XmlNode)) F4
where modelFileId like '%;%'
order by modelFileId
Frank
quelle
2
Select distinct PROJ_UID,PROJ_NAME,RES_UID from E2E_ProjectWiseTimesheetActuals
where   CHARINDEX(','+cast(PROJ_UID as varchar(8000))+',', @params) > 0 and  CHARINDEX(','+cast(RES_UID as varchar(8000))+',', @res) > 0
user7678586
quelle
4
Während dieser Code die Frage möglicherweise beantwortet, verbessert die Bereitstellung eines zusätzlichen Kontexts darüber, warum und / oder wie dieser Code die Frage beantwortet, ihren langfristigen Wert.
Drag and Drop
2

Ich habe oben eine Antwort neu geschrieben und sie verbessert:

CREATE FUNCTION [dbo].[CSVParser]
(
  @s        VARCHAR(255),
  @idx      NUMERIC
)
RETURNS VARCHAR(12)
BEGIN
    DECLARE @comma int
    SET @comma = CHARINDEX(',', @s)
    WHILE 1=1
    BEGIN
        IF @comma=0
            IF @idx=1
                RETURN @s
            ELSE
                RETURN ''

        IF @idx=1
        BEGIN
            DECLARE @word VARCHAR(12)
            SET @word=LEFT(@s, @comma - 1)
            RETURN @word
        END

        SET @s = RIGHT(@s,LEN(@s)-@comma)
        SET @comma = CHARINDEX(',', @s)
        SET @idx = @idx - 1
    END
    RETURN 'not used'
END

Anwendungsbeispiel:

SELECT dbo.CSVParser(COLUMN, 1),
       dbo.CSVParser(COLUMN, 2),
       dbo.CSVParser(COLUMN, 3)
FROM   TABLE
Pete Alvin
quelle
0
CREATE FUNCTION [dbo].[fnSplit](@sInputList VARCHAR(8000), @sDelimiter VARCHAR(8000) = ',')
RETURNS @List TABLE (item VARCHAR(8000))
BEGIN

    DECLARE @sItem VARCHAR(8000)
    WHILE CHARINDEX(@sDelimiter, @sInputList, 0) <> 0
    BEGIN

        SELECT @sItem = RTRIM(LTRIM(SUBSTRING(@sInputList, 1, CHARINDEX(@sDelimiter, @sInputList,0) - 1))),
               @sInputList = RTRIM(LTRIM(SUBSTRING(@sInputList, CHARINDEX(@sDelimiter, @sInputList, 0) + LEN(@sDelimiter),LEN(@sInputList))))

        -- Indexes to keep the position of searching
        IF LEN(@sItem) > 0

        INSERT INTO @List SELECT @sItem

    END

    IF LEN(@sInputList) > 0
    BEGIN

        INSERT INTO @List SELECT @sInputList -- Put the last item in

    END

    RETURN

END
Glyn
quelle