Reputation: 13
I am running into an issue with T-SQL code. There is a CSV file that I need to import and transform into a SQL Server table. The problem is that the CSV file is not correctly format and looks like this:
Recipe,Recipe,Recipe,Recipe,...
0,1,3,4,...
Data1,Data2,Data3,Data4,...
...
The final result would need to be at least like this:
Recipe,0,Data1,...
Recipe,1,Data2,...
Recipe,3,Data3,...
Recipe,4,Data4,...
...
I have used FOR XML PATH to get all rows into one single string but I did not end up with anything good.
The information I have :
Any help to show me the right path would be greatly appreciated!
Thanks!
Upvotes: 0
Views: 597
Reputation: 81970
Example
Declare @S varchar(max) = 'Recipe,Recipe,Recipe,Recipe
0,1,3,4
Data1,Data2,Data3,Data4'
;with cte as (
Select CN=A.RetSeq
,RN=B.RetSeq
,Value=B.RetVal
From [dbo].[tvf-Str-Parse](@S,char(13)+char(10)) A
Cross Apply [dbo].[tvf-Str-Parse](A.RetVal,',') B
)
Select Str = Stuff((Select ',' +Value From cte Where RN=A.RN Order By CN For XML Path ('')),1,1,'')
From (Select Distinct RN from cte) A
Order By A.RN
Returns
Str
Recipe,0,Data1
Recipe,1,Data2
Recipe,3,Data3
Recipe,4,Data4
The Function if Interested
CREATE FUNCTION [dbo].[tvf-Str-Parse] (@String varchar(max),@Delimiter varchar(10))
Returns Table
As
Return (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(@String,@Delimiter,'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
);
EDIT - OPTION WITHOUT FUNCTION
Declare @S varchar(max) = 'Recipe,Recipe,Recipe,Recipe
0,1,3,4
Data1,Data2,Data3,Data4'
;with cte as (
Select CN=A.RetSeq
,RN=B.RetSeq
,Value=B.RetVal
From (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(@S,char(13)+char(10),'§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
) A
Cross Apply (
Select RetSeq = row_number() over (order by 1/0)
,RetVal = ltrim(rtrim(B.i.value('(./text())[1]', 'varchar(max)')))
From (Select x = Cast('<x>' + replace((Select replace(A.RetVal,',','§§Split§§') as [*] For XML Path('')),'§§Split§§','</x><x>')+'</x>' as xml).query('.')) as A
Cross Apply x.nodes('x') AS B(i)
) B
)
Select Str = Stuff((Select ',' +Value From cte Where RN=A.RN Order By CN For XML Path ('')),1,1,'')
From (Select Distinct RN from cte) A
Order By RN
Edit JSON OPTION -- Correcting for Double Quotes
Declare @S varchar(max) = 'Recipe,Recipe,Recipe,Recipe
1,,3,4
Data1,Data2,Data"3,Data4'
;with cte as (
Select CN = A.[key]
,RN = B.[Key]
,Value = replace(B.Value,'||','"')
From OpenJSON('["'+replace(replace(@S,'"','||'),char(13)+char(10),'","')+'"]') A
Cross Apply (
Select *
From OpenJSON('["'+replace(A.Value,',','","')+'"]')
) B
)
Select Str = Stuff((Select ',' +Value From cte Where RN=A.RN Order By CN For XML Path ('')),1,1,'')
From (Select Distinct RN from cte) A
Order By RN
Returns
Str
Recipe,1,Data1
Recipe,,Data2 -- null (2 is missing
Recipe,3,Data"3 -- has double quote
Recipe,4,Data4
Upvotes: 1