Search code examples
sqlsql-serversplitsql-server-2000

SQL Server: Splitting string by '/' and put each split element into a different column


I have a table on an external site that I need to copy to a local DB, but with some transformations. One of the columns I have to heavily modify is called product_url. The URL is in the form site.com\category\sub-category\brand\model#.

The table in my local db will have 4 columns to hold this data. They will be category, sub-category, brand and model#. So, I will have to first trim the site.com (I did this using truncate), but now I have to parse \category\sub-category\brand\model#

I found a UDF from SO that I think will help out. Here it is:

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

Now I am having trouble using this function. Probably due to my lack of experience with UDF's.

Here is what I have now:

select s from
dbo.SplitString(select substring(product_url, 8, len(product_url)) 
            from Products, '/')
where zeroBasedOccurance=0 AS Category

This is obviously not even syntactically correct.

I am wondering if I am going about this the best way. I am not yet much of a DBA, so I am having a hard time wrapping my head around this issue. I just need to figure out how to apply this UDF ~4 times for each row in the product_url table.


Solution

  • Not sure about your function, but here is mine:

    CREATE FUNCTION dbo.FN_PARSENAME(@chunk VARCHAR(4000), @delimiter CHAR(1), @index INT )
    RETURNS VARCHAR(1000)
    AS
    BEGIN
    DECLARE
        @curIndex INT = 0,
        @pos INT = 1,
        @prevPos INT = 0,
        @result VARCHAR(1000)
    
    WHILE @pos > 0
    BEGIN
    
        SET @pos =  CHARINDEX(@delimiter, @chunk, @prevPos);
    
        IF(@pos > 0)
        BEGIN -- Characters between position and previous position
            SET @result = SUBSTRING(@chunk, @prevPos, @pos-@prevPos)
        END
        ELSE
        BEGIN -- Last Delim
            SET @result = SUBSTRING(@chunk, @prevPos, LEN(@chunk))
        END
    
        IF(@index = @curIndex)
        BEGIN
            RETURN @result
        END
    
        SET @prevPos = @pos + 1
        SET @curIndex = @curIndex + 1;
    END
    RETURN '' -- Else Empty
    END
    

    You call it as such:
    SELECT Address_Line1 = dbo.fn_Parsename(Merged,'|', 0) FROM Table

    Wherein Merged is the field that is delimited, the '|' is the delimiter, so you would make it '\', and the 0 is which portion of the string you want, 0 being the first, on up.

    For your example it would be:

    SELECT category = dbo.fn_Parsename(product_url,'\', 1)
         , sub-category = dbo.fn_Parsename(product_url,'\', 2)
         , brand = dbo.fn_Parsename(product_url,'\', 3)
         , model# = dbo.fn_Parsename(product_url,'\', 4)
    FROM Table 
    

    Or maybe 0-3 depending.

    I'm pretty confident I adapted that from something I found, perhaps even on SO, but I can't recall who would deserve credit.