Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Turning a Comma Separated string into individual rows

I have a SQL Table like this:

| SomeID         | OtherID     | Data +----------------+-------------+------------------- | abcdef-.....   | cdef123-... | 18,20,22 | abcdef-.....   | 4554a24-... | 17,19 | 987654-.....   | 12324a2-... | 13,19,20 

is there a query where I can perform a query like SELECT OtherID, SplitData WHERE SomeID = 'abcdef-.......' that returns individual rows, like this:

| OtherID     | SplitData +-------------+------------------- | cdef123-... | 18 | cdef123-... | 20 | cdef123-... | 22 | 4554a24-... | 17 | 4554a24-... | 19 

Basically split my data at the comma into individual rows?

I am aware that storing a comma-separated string into a relational database sounds dumb, but the normal use case in the consumer application makes that really helpful.

I don't want to do the split in the application as I need paging, so I wanted to explore options before refactoring the whole app.

It's SQL Server 2008 (non-R2).

like image 731
Michael Stum Avatar asked Mar 30 '11 23:03

Michael Stum


People also ask

How do you split comma separated values into rows?

First select Cell B5, go to Data > Text to Columns. Then from the Text to Columns Wizard select Original Data Type: Delimited and click Next. Now choose the Delimiters type: Comma and click Next. After that, choose the Destination cell (here Cell C5) and press Finish.


1 Answers

You can use the wonderful recursive functions from SQL Server:


Sample table:

CREATE TABLE Testdata (     SomeID INT,     OtherID INT,     String VARCHAR(MAX) );  INSERT Testdata SELECT 1,  9, '18,20,22'; INSERT Testdata SELECT 2,  8, '17,19'; INSERT Testdata SELECT 3,  7, '13,19,20'; INSERT Testdata SELECT 4,  6, ''; INSERT Testdata SELECT 9, 11, '1,2,3,4'; 

The query

WITH tmp(SomeID, OtherID, DataItem, String) AS (     SELECT         SomeID,         OtherID,         LEFT(String, CHARINDEX(',', String + ',') - 1),         STUFF(String, 1, CHARINDEX(',', String + ','), '')     FROM Testdata     UNION all      SELECT         SomeID,         OtherID,         LEFT(String, CHARINDEX(',', String + ',') - 1),         STUFF(String, 1, CHARINDEX(',', String + ','), '')     FROM tmp     WHERE         String > '' ) SELECT     SomeID,     OtherID,     DataItem FROM tmp ORDER BY SomeID; -- OPTION (maxrecursion 0) -- normally recursion is limited to 100. If you know you have very long -- strings, uncomment the option 

Output

 SomeID | OtherID | DataItem  --------+---------+----------  1      | 9       | 18         1      | 9       | 20         1      | 9       | 22         2      | 8       | 17         2      | 8       | 19         3      | 7       | 13         3      | 7       | 19         3      | 7       | 20         4      | 6       |            9      | 11      | 1          9      | 11      | 2          9      | 11      | 3          9      | 11      | 4         
like image 132
RichardTheKiwi Avatar answered Sep 26 '22 08:09

RichardTheKiwi