Question

Day #3 with SQL Server.

I am trying to combine 2 columns of delimited data into one output from a Table Valued Function. Here is my data:

enter image description here

I would like the data to be processed and placed into a table in the following format:

enter image description here

I am currently trying to use this CROSS APPLY TSQL statement, but I don't know what I'm doing.

USE [Metrics]
INSERT INTO dbo.tblSplitData(SplitKey, SplitString, SplitValues)
SELECT d.RawKey, c.*, e.*
FROM dbo.tblRawData d
CROSS APPLY dbo.splitstringcomma(d.DelimitedString) c, dbo.splitstringcomma(d.DelimitedValues) e

My research on CROSS APPLY has broad context, and I don't understand how it should be applied in this scenario. Do I need a subquery with an additional CROSS APPLY and a join to combine the returns from the two Table Valued Functions?

Here is the split function I was using originally (I can't remember the author to credit them):

CREATE FUNCTION [dbo].[splitstring] ( @stringToSplit VARCHAR(MAX), @Delimiter CHAR(1))
RETURNS
 @returnList TABLE ([Name] [nvarchar] (500))
AS
BEGIN

 DECLARE @name NVARCHAR(255)
 DECLARE @pos INT

 WHILE CHARINDEX(@Delimiter, @stringToSplit) > 0
 BEGIN
  SELECT @pos  = CHARINDEX(@Delimiter, @stringToSplit)  
  SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

  INSERT INTO @returnList 
  SELECT @name

  SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
 END

 INSERT INTO @returnList
 SELECT @stringToSplit

 RETURN
END

Edit & Revised Query

USE [Metrics] 
INSERT INTO dbo.tblSplitData(SplitKey, SplitString, SplitValues)
SELECT s.RawKey, s.SplitString, v.SplitValues
FROM (
SELECT d.RawKey, d.DelimitedString,
 c.item SplitString, c.rn
FROM dbo.tblRawData d
CROSS APPLY dbo.splitstring(d.DelimitedString, ',') c
) s

INNER JOIN

(
SELECT d.RawKey, d.DelimitedValues,
 c.item SplitValues, c.rn
FROM dbo.tblRawData d
CROSS APPLY dbo.splitstring(d.DelimitedValues, ',') c
) v
on s.RawKey = v.RawKey
and s.rn = v.rn;
Was it helpful?

Solution

It might be easier to answer this if we could see your split string function. My answer is using a version of my split function that I have.

I would include in your split function a row number that you can use to JOIN the split string and the split values.

Split function:

CREATE FUNCTION [dbo].[Split](@String varchar(MAX), @Delimiter char(1))       
returns @temptable TABLE (items varchar(MAX), rn int)       
as       
begin      
    declare @idx int       
    declare @slice varchar(8000)   
    declare @rn int = 1 -- row number that increments with each value in the delimited string

    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, rn) values(@slice, @rn)       

        set @String = right(@String,len(@String) - @idx)       
        set @rn = @rn +1

        if len(@String) = 0 break       
    end   
return 
end;

Then if you have multiple columns to split, you could use a query similar to the following:

INSERT INTO dbo.tblSplitData(SplitKey, SplitString, SplitValues)
select s.rawkey,
  s.splitstring,
  v.splitvalues
from
(
  SELECT d.RawKey, d.delimitedstring, d.delimitedvalues, 
    c.items SplitString, 
    c.rn
  FROM dbo.tblRawData d
  CROSS APPLY dbo.Split(d.DelimitedString, ',') c
) s
inner join
(
  SELECT d.RawKey, d.delimitedstring, d.delimitedvalues, 
    c.items SplitValues, 
    c.rn
  FROM dbo.tblRawData d
  CROSS APPLY dbo.Split(d.DelimitedValues, ',') c
) v
  on s.rawkey = v.rawkey
  and s.delimitedstring = v.delimitedstring
  and s.rn = v.rn;

See SQL Fiddle with Demo

This uses two subqueries that generate the list of split values, then they are joined using the row number created by the split function.

OTHER TIPS

Since you are on Sql Server 2008 .You can do this without a UDF using XML.

;WITH CTE1 AS
( 
    SELECT *
    ,RN= Row_Number() OVER( Partition BY DelemitedString,DelimitedValues,RawKey,TableID ORDER BY TableID)
     FROM 
    (
    SELECT *
    ,DelimitedStringXML = CAST('<d>'+REPLACE(DelemitedString,',','</d><d>')+'</d>' AS XML)
    ,DelimitedValueXML = CAST('<d>'+REPLACE(DelimitedValues,',','</d><d>')+'</d>' AS XML)

     FROM dbo.tblRawData
    ) as t
    Cross Apply
    (
    SELECT y.value('.', 'VARCHAR(30)') AS SplitString FROM DelimitedStringXML.nodes('//d') as  x(y)

    ) as b
)
,CTE2 AS 
(
    SELECT *
    ,RN= Row_Number() OVER( Partition BY DelemitedString,DelimitedValues,RawKey,TableID ORDER BY TableID)
     FROM 
    (
    SELECT *
    ,DelimitedStringXML = CAST('<d>'+REPLACE(DelemitedString,',','</d><d>')+'</d>' AS XML)
    ,DelimitedValueXML = CAST('<d>'+REPLACE(DelimitedValues,',','</d><d>')+'</d>' AS XML)

     FROM dbo.tblRawData
    ) as t
    CROSS APPLY
    (
    SELECT h.value('.', 'VARCHAR(30)') AS SplitValue FROM DelimitedValueXML.nodes('//d') as  g(h)

    ) as c
)


SELECT a.RawKey,a.SplitString,b.SplitValue 
FROM CTE1 as a
INNER JOIN CTE2 as b
    on  a.TableID= b.TableID
    AND a.RN = b.RN

Here is SQLFiddle Demo

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top