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:
I would like the data to be processed and placed into a table in the following format:
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;
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;
This uses two subqueries that generate the list of split values, then they are joined using the row number created by the split function.
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
来源:https://stackoverflow.com/questions/16362318/using-cross-apply-for-more-than-one-column