Reputation: 31
I want to display a string in a table format as shown below:
For a string like 'hi,is,1,question,thanks,.,.,n'
I need this result:
column1 column2 column3 column4 ..... column
hi is 1 question ..... n
Upvotes: 0
Views: 1843
Reputation: 67291
This is not trivial. You will find a lot of examples how to split your string in a set of fragments. And you will find a lot of examples how to pivot a row set to a single row. But - adding quite some difficulty - you have an unknown count of columns. There are three approaches:
EXEC
. But this will not work in VIEWs or iTVFs, nor will it work against a table.One example for the first was this
DECLARE @str VARCHAR(1000)='This,is,a,string,with,n,elements,...';
SELECT p.*
FROM
(
SELECT A.[value]
,CONCAT('Column',A.[key]+1) AS ColumnName
FROM OPENJSON('["' + REPLACE(@str,',','","') + '"]') A
) t
PIVOT
(
MAX(t.[value]) FOR ColumnName IN(Column1,Column2,Column3,Column4,Column5,Column6,Column7,Column8,Column9 /*add as many as you need*/)
) p
Hint: My approach to split the string uses OPENJSON
, not available before version 2016. But there are many other approaches you'll find easily. It's just an example to show you the combination of a splitter with PIVOT
using a running index to build up a column name.
And the same example with a dynamically created column list was this:
DECLARE @str VARCHAR(1000)='This,is,a,string,with,n,elements,...';
DECLARE @CountElements INT=LEN(@str)-LEN(REPLACE(@str,',',''))+1;
DECLARE @columnList NVARCHAR(MAX)=
STUFF((
SELECT TOP(@CountElements)
CONCAT(',Column',ROW_NUMBER() OVER(ORDER BY (SELECT 1)))
FROM master..spt_values /*has a lot of rows*/
FOR XML PATH('')
),1,1,'');
DECLARE @Command NVARCHAR(MAX)=
N'SELECT p.*
FROM
(
SELECT A.[value]
,CONCAT(''Column'',A.[key]+1) AS ColumnName
FROM OPENJSON(''["'' + REPLACE(''' + @str + ''','','',''","'') + ''"]'') A
) t
PIVOT
(
MAX(t.[value]) FOR ColumnName IN(' + @columnList + ')
) p;';
EXEC(@Command);
Hint: The statement created is exactly the same as above. But the column list in the pivot's IN
is created dynamically. This will work with (almost) any count of words generically.
If you need more help, please use the edit option of your question and provide some more details.
If you need this against a table, you might try something along this:
DECLARE @tbl TABLE(ID INT IDENTITY,YourList NVARCHAR(MAX));
INSERT INTO @tbl VALUES('This,is,a,string,with,n,elements,...')
,('And,one,more');
SELECT *
,CAST('<x>' + REPLACE((SELECT t.YourList AS [*] FOR XML PATH('')),',','</x><x>') + '</x>' AS XML) AS Splitted
FROM @tbl t
This will return your list as an XML like
<x>This</x>
<x>is</x>
<x>a</x>
<x>string</x>
<x>with</x>
<x>n</x>
<x>elements</x>
<x>...</x>
You can grab - if needed - each element by its index like here
TheXml.value('/x[1]','nvarchar(max)') AS Element1
Upvotes: 1
Reputation: 635
DECLARE @string VARCHAR(MAX);
SET @string = 'hi,is,1,question,thanks,.,.,n';
DECLARE @SQL VARCHAR(MAX);
SET @SQL = 'SELECT ''' + REPLACE(@string, ',', ''',''') + '''';
EXEC (@SQL);
Add SELECT ' at beginning and ' at the end of string
Replace all , with ',' inside string
So string 'hi,is,1,question,thanks,.,.,n' is replace by 'SELECT 'hi','is','1','question','thanks','.','.','n''
PS: If you want to use it on column you will have to combine it with CURSOR
Update
DECLARE @table TABLE
(
ID INT IDENTITY,
string VARCHAR(MAX)
);
INSERT INTO @table
VALUES
('This,is,a,string,,n,elements,..');
INSERT INTO @table
VALUES
('And,one,more');
INSERT INTO @table
VALUES
('Ugly,but,works,,,Yay!,..,,,10,11,12,13,14,15,16,17,18,19,..');
SELECT * FROM @table
DECLARE @string_to_split VARCHAR(MAX);
DECLARE @sql_query_to_execute VARCHAR(MAX);
DECLARE @max_elements INT, @id INT, @i INT;
SET @i = 1;
DECLARE string_cursor CURSOR FOR SELECT ID, string FROM @table;
SELECT @max_elements = MAX(LEN(string) - LEN(REPLACE(string, ',', ''))) + 1 -- Find max number of elements */
FROM @table;
IF OBJECT_ID('tempdb..##my_temp_table_for_splitted_columns') <> 0 -- Create new temp table with valid amount of columns
DROP TABLE ##my_temp_table_for_splited_columns;
SET @sql_query_to_execute = 'create table ##my_temp_table_for_splitted_columns ( ID int,';
WHILE @i <= @max_elements
BEGIN
SET @sql_query_to_execute = @sql_query_to_execute + ' Col' + CAST(@i AS VARCHAR(max)) + ' varchar(25), ';
SET @i = @i + 1;
END;
SELECT @sql_query_to_execute = SUBSTRING(@sql_query_to_execute, 1, LEN(@sql_query_to_execute) - 1) + ')';
EXEC (@sql_query_to_execute);
/* Split string for each row */
OPEN string_cursor;
FETCH NEXT FROM string_cursor
INTO @id,
@string_to_split
WHILE @@FETCH_STATUS = 0
BEGIN
SET @i = MAX(LEN(@string_to_split) - LEN(REPLACE(@string_to_split, ',', ''))) + 1; -- check amount of columns for current string
WHILE @i < @max_elements
BEGIN
SET @string_to_split = @string_to_split + ','; -- add missing columns
SET @i = @i + 1;
END;
SET @sql_query_to_execute = 'SELECT ' + CAST(@id AS VARCHAR(MAX)) + ',''' + REPLACE(@string_to_split, ',', ''',''') + '''';
INSERT INTO ##my_temp_table_for_splitted_columns --insert result to temp table
EXEC (@sql_query_to_execute);
FETCH NEXT FROM string_cursor
INTO @id,
@string_to_split;
END;
CLOSE string_cursor;
DEALLOCATE string_cursor;
SELECT *
FROM ##my_temp_table_for_splitted_columns;
Upvotes: 1