How to split a comma-separated value to columns

后端 未结 30 3801
刺人心
刺人心 2020-11-21 04:38

I have a table like this

Value   String
-------------------
1       Cleo, Smith

I want to separate the comma delimited string into two colu

相关标签:
30条回答
  • 2020-11-21 05:04

    I re-wrote an answer above and made it better:

    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
    

    Example usage:

    SELECT dbo.CSVParser(COLUMN, 1),
           dbo.CSVParser(COLUMN, 2),
           dbo.CSVParser(COLUMN, 3)
    FROM   TABLE
    
    0 讨论(0)
  • 2020-11-21 05:08

    xml base answer is simple and clean

    refer this

    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)
    
    0 讨论(0)
  • 2020-11-21 05:08

    I encountered a similar problem but a complex one and since this is the first thread i found regarding that issue i decided to post my finding. i know it is complex solution to a simple problem but i hope that i could help other people who go to this thread looking for a more complex solution. i had to split a string containing 5 numbers (column name: levelsFeed) and to show each number in a separate column. for example: 8,1,2,2,2 should be shown as :

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

    Solution 1: using XML functions: this solution for the slowest solution by far

    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)
    

    Solution 2: using Split function and pivot. (the split function split a string to rows with the column name Data)

    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
    

    Solution 3: using string manipulations functions - fastest by small margin over solution 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
    

    since the levelsFeed contains 5 string values i needed to use the substring function for the first string.

    i hope that my solution will help other that got to this thread looking for a more complex split to columns methods

    0 讨论(0)
  • 2020-11-21 05:09

    Using instring function :)

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

    Used two functions,
    1. substring(string, position, length) ==> returns string from positon to length
    2. instr(string,pattern) ==> returns position of pattern.

    If we don’t provide length argument in substring it returns until end of string

    0 讨论(0)
  • 2020-11-21 05:10
    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
    
    0 讨论(0)
  • 2020-11-21 05:10

    With 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
    
    0 讨论(0)
提交回复
热议问题