Avatar of nickgross19
nickgross19

asked on 

SQL question

I am using MS SQL Server 2008 and I need to create a view from values in a table.  
The table the view will pull its data from has a column that contains values which are separated by commas.  For example the information in one field in this column might be:  123kdkd, 2939439

I want to take each value that is in the field and put it into one field in the view.  So if I were to do this for the sample data I provided, my view would look like this

      ID                  Value
 -----------     |   -----------
       1            |   123kdkd
       2            |   2939439

I think I might need to use the charindex() and substring() functions and do a loop, but I am new to T-SQL and haven't done a loop in SQL before.
Microsoft SQL Server 2008

Avatar of undefined
Last Comment
nickgross19
Avatar of knightEknight
knightEknight
Flag of United States of America image

Is there always just two values?  e.g.  123kdkd,2939439

Or can there be more than one?  123kdkd,2939439,xxxyyyzzz,111,222,333
Avatar of knightEknight
knightEknight
Flag of United States of America image

If just two, then do this:

select ID, select SUBSTRING(Value,0,charindex(',',Value)) as col1, SUBSTRING(Value,charindex(',',Value)+1,len(Value)) as col2
Avatar of knightEknight
knightEknight
Flag of United States of America image

... from yourTable
Avatar of knightEknight
knightEknight
Flag of United States of America image

oops, messed up the select, it should be (again, if there are always only two values in the string)

select ID, SUBSTRING(Value,0,charindex(',',Value)) as col1, SUBSTRING(Value,charindex(',',Value)+1,len(Value)) as col2
from yourTable
Avatar of knightEknight
knightEknight
Flag of United States of America image

and to make a view out of it:

create view myView as
select ID, SUBSTRING(Value,0,charindex(',',Value)) as col1, SUBSTRING(Value,charindex(',',Value)+1,len(Value)) as col2
from yourTable
GO

select * from myView
Avatar of nickgross19
nickgross19

ASKER

There are usually just two, but to be safe I want to take into account the possibility that there could be an unknown number more.
Avatar of nickgross19
nickgross19

ASKER

Consequently, I can't just do 3 or 4 replace functions because there could be more or less values than that!
Avatar of knightEknight
knightEknight
Flag of United States of America image

In that case you will need a function to split the CSV string.  First create this function:

create FUNCTION [dbo].[csv1] (@Source VARCHAR(MAX), @rowDelim VARCHAR(max)=',') 
    RETURNS @Result TABLE (ID int identity, col1 varchar(MAX)) 
    WITH SCHEMABINDING
AS
BEGIN
	IF isNull(@rowDelim,'') in (char(10),'')
	BEGIN
		SELECT @rowDelim = char(13)+char(10)
	END
	ELSE
	BEGIN
		SELECT @Source = replace( @Source, @rowDelim+char(13), @rowDelim )
		SELECT @Source = replace( @Source, @rowDelim+char(10), @rowDelim )
	END

	SELECT @Source = rtrim(ltrim(@Source))
	SELECT @Source = @Source+@rowDelim  WHERE RIGHT(@Source,1) != @rowDelim 

	DECLARE @rowDelimPos int=0, @StartShift int=1, @LenSource int=len(@Source)
	WHILE @StartShift <= @LenSource 
	BEGIN 
		SELECT @rowDelimPos = charindex( @rowDelim, @Source, @StartShift )
		INSERT INTO @Result VALUES ( substring(@Source,@StartShift,@rowDelimPos-@StartShift) )
		SELECT @StartShift = @rowDelimPos + len(@rowDelim) 
	END

	RETURN
END

Open in new window

Avatar of knightEknight
knightEknight
Flag of United States of America image

... stand by, i'll be posting how to use it momentarily..
ASKER CERTIFIED SOLUTION
Avatar of JestersGrind
JestersGrind
Flag of United States of America image

Blurred text
THIS SOLUTION IS ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
Avatar of knightEknight
knightEknight
Flag of United States of America image

okay, i hit some strangeness and it took me a minute to figure it out.

But before that you must realize that it is not possible to create a view with a variable number of columns.  Therefore you must choose a finite number -- in this case we'll use 4.

I use the function from the previous post along with outer apply to pull in the extra columns, but hit a snag when some of the Values had more commas than others.  So I employed a trick and appended extra commas on the Value column in each outer apply.  This seems to do the trick...  See below:

However, this won't be a very efficient query -- it will probably run slow against very large data sets.
create view MyView as
select T.ID,  F1.col1 as VC1,  F2.col1 as VC2,  F3.col1 as VC3,  F4.col1 as VC4
from MyTable T
outer apply dbo.csv1( T.Value+',,,,', ',' ) F1
outer apply dbo.csv1( T.Value+',,,,', ',' ) F2
outer apply dbo.csv1( T.Value+',,,,', ',' ) F3
outer apply dbo.csv1( T.Value+',,,,', ',' ) F4
where F1.ID=1
  and F2.ID=2
  and F3.ID=3
  and F4.ID=4

Open in new window

Avatar of knightEknight
knightEknight
Flag of United States of America image

btw - I just noticed that your sample table has the exact columns - ID and Value - as the function.  This is just a coincidence.  I mention it only because it may cause some confusion, so note the table qualifiers in the post above to keep it straight.  :)
Avatar of knightEknight
knightEknight
Flag of United States of America image

Also note that I appended 4 commas ',,,,' to Value in the outer apply clauses -- this is to match the 4 columns in the view.
As it is now, rows with NULL for Value (in your table) will be excluded from the results.  Let me know if you want to include them (all the VC# columns will be null for rows like this).
Avatar of knightEknight
knightEknight
Flag of United States of America image

Note that the view suggested above will handle different Values with varying numbers of commas (up to 4), so it will still work even if your table looks like this:

1    123kdkd,2939439
2    123kdkd,2939439,xxxyyyzzz,999
3    xyzpdq,yyz,123
Avatar of knightEknight
knightEknight
Flag of United States of America image

correction - up to 3 commas representing 4 columns
>>But before that you must realize that it is not possible to create a view with a variable number of columns. <<
But that is just the point, it only has two: ID and Value.  Which is a lot simpler and makes it a perfect candidate for CROSS APPLY as JestersGrind showed here http:#a36933430 
Avatar of knightEknight
knightEknight
Flag of United States of America image

I believe he was asking for a separate column in the view for each value between commas in the Value column, of which there could be 1 to n.  The view itself cannot have 3 columns with one query and 5 with the next based on how many commas are in Value.
Avatar of Anthony Perkins
Anthony Perkins
Flag of United States of America image

The author's output in the original question only has two columns: ID and Value.  If this has now changed they need to clarify.
Avatar of knightEknight
knightEknight
Flag of United States of America image

He did so here: http:#36933371

>> There are usually just two, but to be safe I want to take into account the possibility that there could be an unknown number more. <<

...which led to my reply:

>> But before that you must realize that it is not possible to create a view with a variable number of columns. <<
Avatar of nickgross19
nickgross19

ASKER

In my original question I only needed two columns.  The first column would contain the ID and the other column would contain the part number.  SO the two columns would be a candidate key; thus there could be many rows with the same value for ID; but each row with the same ID would have a different part number with it.

Avatar of knightEknight
knightEknight
Flag of United States of America image

exactly, and several early proposals would work for a two-column solution when Value contains just one comma.
But then you asked for a multi-column solution for when Value contained multiple commas (e.g. columns), which sparked the later proposals.
My reply about the view was addressing this.
Avatar of JestersGrind
JestersGrind
Flag of United States of America image

By splitting the string and reducing the horizontal, comma delimited string to a vertical, two column table, it doesn't matter how many elements are in the original string.  You just end up getting a row back for each element in the string.

Greg

Avatar of knightEknight
knightEknight
Flag of United States of America image

Yes, both functions above do this.  The trick is to make it work when there is more than one row of Values containing more than one comma -- especially if Value in one row contains x commas and in another row it contains y commas.
Avatar of Anthony Perkins
Anthony Perkins
Flag of United States of America image

I am so confused...

I am glad you guys understand the authors requirements.
Avatar of nickgross19
nickgross19

ASKER

This code from what I can tell shows the record ID and each value that was located in the column with values delimited by commas.

Thanks!
Microsoft SQL Server 2008
Microsoft SQL Server 2008

Microsoft SQL Server 2008 is a suite of relational database management system (RDBMS) products providing multi-user database access functionality.Component services include integration (SSIS), reporting (SSRS), analysis (SSAS), data quality, master data, T-SQL and performance tuning. Major improvements include the Always On technologies and support for unstructured data types.

50K
Questions
--
Followers
--
Top Experts
Get a personalized solution from industry experts
Ask the experts
Read over 600 more reviews

TRUSTED BY

IBM logoIntel logoMicrosoft logoUbisoft logoSAP logo
Qualcomm logoCitrix Systems logoWorkday logoErnst & Young logo
High performer badgeUsers love us badge
LinkedIn logoFacebook logoX logoInstagram logoTikTok logoYouTube logo