MS SQL Server nested data

I need help extracting data from a column that has nested data.

Table = Table1

Columns  =
ID = string (Record IDumber)
Codes = string (Multipule valuse seperated by commas)

Example

ID        |  Codes
1          | ,1000,2002,3002,4000,4000,

How can I extract and separate the values in the codes column
MPDenverAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

PortletPaulEE Topic AdvisorCommented:
Depending on the version you can either use STRING_SPLIT() {SQL Server 2017 on} or build your own split_string function

Here is a split_string function if you don't already have one (there are many available):
CREATE FUNCTION dbo.Split_String /* dbo.SplitStrings_Moden https://sqlperformance.com/2012/07/t-sql-queries/split-strings */
(
   @List NVARCHAR(MAX),
   @Delimiter NVARCHAR(255)
)
RETURNS TABLE
WITH SCHEMABINDING AS
RETURN
  WITH E1(N)        AS ( SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
                         UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1),
       E2(N)        AS (SELECT 1 FROM E1 a, E1 b),
       E4(N)        AS (SELECT 1 FROM E2 a, E2 b),
       E42(N)       AS (SELECT 1 FROM E4 a, E2 b),
       cteTally(N)  AS (SELECT 0 UNION ALL SELECT TOP (DATALENGTH(ISNULL(@List,1))) 
                         ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E42),
       cteStart(N1) AS (SELECT t.N+1 FROM cteTally t
                         WHERE (SUBSTRING(@List,t.N,1) = @Delimiter OR t.N = 0))
SELECT 
    Item = SUBSTRING(@List, s.N1, ISNULL(NULLIF(CHARINDEX(@Delimiter,@List,s.N1),0)-s.N1,8000))
FROM cteStart s
;

Open in new window

-- if before SQL Server 2017

select
    id, item
from table1
cross apply dbo.split_string(codes,',')
where item <> ''
;

-- if using SQL Server 2017 or later
select
    id, value
from table1
cross apply string_split(codes,',')
where value <> ''
;

Open in new window

result
| id | item |
|----|------|
|  1 | 1000 |
|  1 | 2002 |
|  1 | 3002 |
|  1 | 4000 |
|  1 | 4000 |
        

| id | value |
|----|-------|
|  1 |  1000 |
|  1 |  2002 |
|  1 |  3002 |
|  1 |  4000 |
|  1 |  4000 |
        

Open in new window

see: http://sqlfiddle.com/#!18/0270a/1
CREATE TABLE Table1
    ([ID] int, [Codes] varchar(300))
;
  
INSERT INTO Table1
    ([ID], [Codes])
VALUES
    (1, ',1000,2002,3002,4000,4000,')
;

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Olaf DoschkeSoftware DeveloperCommented:
It always was and stilll is a nice way to be able to filter multiple codes by using something splitting such a string into multiple records to inner join with them.

In the past you had to do a user-defined function for splitting CSV values based on a tally table for that, see http://www.sqlservercentral.com/articles/Tally+Table/72993/

Since a few years, there is STRING_SPLIT (Starting in SQL Server 2016 and minimum COMPATIBILITY_LEVEL 130)
DECLARE @data as Table (ID int, [codes] Varchar(128))

INSERT INTO @data values (1,',1000,2002,3002,4000,4000,'),(2,'123,,456')

SELECT ID,value as Code from @data
cross apply string_split([codes],',') where value<>''

Open in new window


You may want to trim off the leftmost and rightmost comma in your case, I simply did that with the WHERE value<>'', but it might be valid some items in the list are empty, especially in cases this is not about numbers.

Notice the type of value still is varchar (read books online about String_Split), to get numbers simply use CAST or CONVERT.

PS: You might even find such a split function in your database, specialized on the case of CSV delimited with extra commas. I can see how that may simplify code finding all items between two commas, as begin and end of a field are no special case anymore.

Bye, Olaf.
0
PortletPaulEE Topic AdvisorCommented:
@Olaf
Yes, string_split was introduced at SQL Server 2016. Sorry. I had just recently used string_agg and string_split in an answer it was string_agg that came in 2017. Cheers.
1
MPDenverAuthor Commented:
Thank You for the help
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Query Syntax

From novice to tech pro — start learning today.