August 25, 2004 at 9:35 am
I need to return multiple values to a single comma separated column. Here's an example:
returned data
Joe 123
Joe 456
Joe 789
Ken 357
I need it to return:
Joe 123,456,789
Ken 357
Any suggestions? Thanks
August 25, 2004 at 10:52 am
DECLARE @text VARCHAR(2000)
SELECT @text = @text + RTRIM(LTRIM(column_value)) + ','
FROM Sometable
August 25, 2004 at 11:20 am
Thanks for the reply.
We are currently using the suggestion made, but we were hoping to accomplish it with an sql statement or built-in function (i.e., grouping or something like that), not a stored procedure. We can continue to use the sp, just hoping there was some neat little feature of tsql that we hadn't found yet.
August 25, 2004 at 11:36 am
hmmm...sounds like you need to do a crosstab and then concatenate the fields. Does your second column have a fixed # of possibilities, or is it a numeric field? I can think of some ways to do it if it's got a fixed number of values.
Otherwise I think it's a stored procedure thing, e.g.:
SET NOCOUNT ON
CREATE TABLE #test (Fname Varchar(20), val INT, ID INT IDENTITY)
INSERT #test (fname,val) Values('Joe','123')
INSERT #test (fname,val) Values('Joe','456')
INSERT #test (fname,val) Values('Joe','789')
INSERT #test (fname,val) Values('Ken','357')
SELECT * INTO #t
FROM #test ORDER BY fname, val
Create Table #v (Val varchar(255))
DECLARE
@fname varchar(20)
, @val Varchar(255)
, @STR Varchar(255)
, @ctr INT
, @max-2 INT
SET @ctr = 1
SET @max-2 = (SELECT MAX(ID) FROM #t)
SET @fname = ''
WHILE @ctr <= @max-2
BEGIN
IF @fname = (SELECT fname FROM #t WHERE ID = @ctr)
BEGIN
SET @val = @val + ',' + CAST((SELECT val FROM #t WHERE ID = @ctr) AS Varchar(255))
END
ELSE
BEGIN
IF @val IS NOT NULL
INSERT #v Values(@val)
SET @fname = (SELECT fname FROM #t WHERE ID = @ctr)
SET @val = @fname + ' ' + CAST((SELECT val FROM #t WHERE ID = @ctr) AS Varchar(255))
END
SET @ctr = @ctr + 1
IF @ctr > @max-2
INSERT #v Values(@val)
END
SELECT * FROM #v
DROP TABLE #v
DROP TABLE #t
DROP TABLE #test
Good luck!
August 25, 2004 at 11:52 am
Our second column does not have a fixed number of values. The input is integer, but will be going to a text column. Looks like a stored procedure is our best option (or only option )
Thanks
August 25, 2004 at 12:17 pm
Use cowboyferrier's method, and write it as a UDF (assuming you're on 2000).
Then in a select you can say:
SELECT name, dbo.myUDF_get_val_list( primarykeyhere ) AS val_list FROM tablename...
Then this can be made into a view if you like.
August 26, 2004 at 3:11 am
I vote for UDF, too... see my reply in another current thread :
http://www.sqlservercentral.com/forums/shwmessage.aspx?messageid=133911
This question keeps popping up quite often... I learned this way to create concatenated texts in these forums, half a year ago - and found it very useful.
HTH, Vladan
August 26, 2004 at 3:44 am
I noted that the main subject of that thread was "to avoid using a cursor".
Just be aware that while "UDF" doesn't spell like "cursor", the implementation of many UDFs shows a "cursory behaviour" - ie what you can get from a UDF is the exact row-by-row processing as a cursor has.
Sometimes this is no issue, other times it will bite you on larger volumes. Then it can be handy to know that performance degradations may be due to "hidden cursor called UDF"
/Kenneth
August 26, 2004 at 4:12 pm
Hey Dude, I have a quick and easy solution ... I am sure most of the guys do not use COALESCE function. I find it quiet powerful. Using cursor here will not do much harm, if you really hate cursors there are definitly alternate ways, which I am sure you can try on. Just copy and paste into SQL analyser, and boom. BEGIN SET NOCOUNT ON CREATE TABLE #test (Fname Varchar(20), val INT, ID INT IDENTITY) INSERT #test (fname,val) Values('Joe','123') INSERT #test (fname,val) Values('Joe','456') INSERT #test (fname,val) Values('Joe','789') INSERT #test (fname,val) Values('Ken','357')
DECLARE @text varchar(255) DECLARE @m_fname varchar(20)
DECLARE test_cursor CURSOR FOR SELECT DISTINCT fname FROM #test OPEN test_cursor FETCH NEXT FROM test_cursor INTO @m_fname WHILE @@FETCH_STATUS = 0 BEGIN --return concatinated values of entire table select @text = COALESCE(@text,'') + convert(varchar(10),val)+ ',' from #test where fname= @m_fname
select @m_fname + ' ' + left(@text, len(@text)-1) set @text='' --reset @text variable
FETCH NEXT FROM test_cursor INTO @m_fname END CLOSE test_cursor DEALLOCATE test_cursor
DROP TABLE #test END |
August 26, 2004 at 10:27 pm
There is an even simpler and more elegant use the Coalsce() function to "Flatten" a column to a delimited string. I first saw the technique in an article in T-SQL Solutions. At first Glance, I could not believe that it would work, but it does and it performs better than using a cursor or while loop to perform the same operation:
@w_resulttext varchar(8000)
SELECT @w_resulttext = coalesce( @w_resulttext +'|', '') + Name
sysobjects where type = 'U'
@w_resulttext
The trick to this technique is to use the coalesce function to insert the delimiter. Here is how it works:
I had written a bunch of user-defined functions using cursors to "flatten" or "Pivot" data for several parent-child tables. To simplify converting them all to this technique, I wrote a helper proc to generate the code for the technique. It generates a functioning code "template" that can be used directly or modified by adding conditions or joins to other tables:
master
procedure sp__CreateFlattener
sysname
,@p_column sysname
,@p_delimeter varchar(20) = ','
,@p_SQL varchar(8000) = null OUTPUT
@p_SQL = 'Declare @w_resulttext varchar(8000)
+ char(39) + @p_delimeter + char(39) + ', ' + char(39) + char(39) + ') + ' + @p_Column
+ char(13) + char(10) + 'FROM ' + @p_table
+ char(13) + char(10) + 'select @w_resulttext'
@p_sql -- comment this out if you don't want the results printed to message window
0
declare @sql varchar(8000)
sp__createflattener @p_table = 'sysobjects', @p_column = 'Name', @p_delimeter = '|', @p_SQL = @sql OUTPUT
Enjoy!
Kindest Regards,
Clayton
Viewing 10 posts - 1 through 9 (of 9 total)
You must be logged in to reply to this topic. Login to reply