I have a table like this:
ID cst
1 string1;3;string2;string3;34;string4;-1;string5;string6;12;string7;5;string8,string9, 65
2 string10;-3;string11;string12;56;string13;6;string14;string15;9
etc.
Now I want to split the cst column into 5 columns and multiple rows. So like this:
ID C1 C2 C3 C4 C5
1 string1 3 string2 string3 34
1 string4 -1 string5 string6 12
1 string7 5 string8 string9 65
2 string10 -3 string11 string12 56
2 string13 6 string14 string15 9
etc.
How to accomplish this? I am on SQL-server 2017, so I can use the string_split function. The problem with this function is that it produces only one output column...
Preferably I would like yo create an UDF that outputs a table. The function would use these input parameters: the string, the separator character, the number of columns. So the function can be used dynamically with a varying number of columns.
ps. the strings can be of variable length of course.
Try it along this:
Hint: There are some "normal" commas in your sample data. I suspected these as wrong and used semicolons. If this is wrong, you might use a general REPLACE() to use ";" instead of ",".
Create a declared table to simulate your issue
--The query (for almost any version of SQL-Server, find v2017+ as UPDATE below)
The idea in short:
APPLYto add your string casted to XML to the result set. This will help to split the string ("a;b;c" =><x>a</x><x>b</x><x>c</x>)APPLYto create a tally on the fly with a computedTOP-clause. It will return as many virtual rows as there are elements in the XMLsql:column()to grab each element's value by its position and some simple maths to create a grouping key and a running number from 0 to 4 and so on.GROUP BYtogether withMAX(CASE...)to place the values in the fitting column (old-fashioned pivot or conditional aggregation).Hint: If you want this fully generically, with a number of columns not knwon in advance. You cannot use any kind of function or ad-hoc query. You would rather need some kind of dynamic statement creation together with
EXECwithin a stored procedure. to be honest: This might be a case of XY-problem. Such approaches are the wrong idea - at least in almost all situations I can think of.UPDATE for SQL-Server 2017+
You are on v2017, this allows for JSON, which is a bit faster in position safe string splitting. Try this:
The general idea is the same. We transform a string to a JSON-array ("a,b,c" => ["a","b","c"]) and read it with
APPLY OPENJSON(). You can perform the same maths at the "key" column and do the rest as above.Just because it is ready here, this is the full query for v2017+