How to split a comma-separated value to columns

后端 未结 30 4031
刺人心
刺人心 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 04:45

    Try this:

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

    You may find the solution in SQL User Defined Function to Parse a Delimited String helpful (from The Code Project).

    This is the code part from this page:

    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:Clayton_Groom@hotmail.com">Clayton_Groom@hotmail.com</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
    
    0 讨论(0)
  • 2020-11-21 04:46

    Use Parsename() function

    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
    

    Result

    Name    Family
    -----   ------
    Aria    Karimi
    Bab     Karimi
    Joe     Karimi
    
    0 讨论(0)
  • 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
    
    0 讨论(0)
  • 2020-11-21 04:48

    I think following function will work for you:

    You have to create a function in SQL first. Like this

    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
    

    You can call this function, like this:

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

    Implementation:

    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
    

    Result will like this:

    0 讨论(0)
  • 2020-11-21 04:49

    I found that using PARSENAME as above caused any name with a period to get nulled.

    So if there was an initial or a title in the name followed by a dot they return NULL.

    I found this worked for me:

    SELECT 
    REPLACE(SUBSTRING(FullName, 1,CHARINDEX(',', FullName)), ',','') as Name,
    REPLACE(SUBSTRING(FullName, CHARINDEX(',', FullName), LEN(FullName)), ',', '') as Surname
    FROM Table1
    
    0 讨论(0)
提交回复
热议问题