Concatenating field values in one string

  • Hi All.

    I am trying to concatenate multiple field values from a table in one string.

    Example:

    IF Select * from TABLE TEST gives following :

    ColA ColB

    1 John

    1 Josh

    1 Bob

    2 Kathy

    2 Jill

    How would I render it to give below data:

    ColA ColB

    1 John, Josh, Bob

    2 Kathy, Jill

    Can someone give their inputs. Thanks for the help.

  • Here is some code you can work with on this.

    declare @TestTab table (ColA int, ColB Varchar(10));

    insert into @TestTab

    select 1, 'John' union all

    select 1, 'Josh' union all

    select 1, 'Bob' union all

    select 2, 'Kathy' union all

    select 2, 'Jill'

    ;

    select * from @TestTab;

    select

    ColA,

    stuff((select ', ' + ColB from @TestTab t2 where t2.ColA = t1.ColA for xml path('')),1,2,'')

    from

    @TestTab t1

    group by

    ColA;

  • Thanks ! Lynn. Will give it a try.

  • Nice Job Lynn, tried to solve it myself, and I couldn't get to group them. I've seen you use the FOR XML a few times in other posts.

    I got a question though, why do you use stuff at the end, wouldn't a substring function, or a right function be easier?

    And oh, yeah.. when I use FOR XML on a simply column, it does not give the same output. i.e: (ColA)Test1(/ColA)(ColA)TEst2(/ColA) why does appending a string to it stop doing the ColA thing?

    Thanks

    Cheers,

    J-F

  • I am going to have to defer your questions to someone who has a better knowledge of FOR XML PATH. I picked up this little trick here on SSC and it works very well, so when someone asks how to do it (which does happen a lot here on SSC), it's something easy to post back.

  • Thanks Lynn, hope a XML Guru can see this post! 😉

    Cheers,

    J-F

  • Stuff gets rid of a preceding comma at the beginning of the string. That's all. Try the query without it, and you get:

    , John, Josh, Bob

    The Stuff command, as written here, puts a zero-length string in, the 1 tells it to put it at the beginning of the string, and the 2 tells it to replace 2 characters. Thus, it gets rid of the comma-space at the beginning. Can't use Replace, or you'd get rid of all of the commas, which would kind of defeat the purpose.

    I guess I'm not clear on the other question about the XML. Using "path('')" is what gets rid of the column names, if that's what you're asking. Well, it replaces the column names with a zero-length string, to be precise.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • It's the FOR XML PATH part that I am not really sure about myself. That's why I was asking for some help here. I'd like to understand it better myself.

  • Lynn Pettis (3/19/2009)


    It's the FOR XML PATH part that I am not really sure about myself. That's why I was asking for some help here. I'd like to understand it better myself.

    Sent out a "tweet" about it that Grant re-tweeted to expand the knowledge base.

  • Try this, see if it helps:

    if object_id(N'tempdb..#T') is not null

    drop table #T;

    create table #T (

    ID int identity primary key,

    Col1 char(1) not null);

    insert into #T (Col1)

    select substring('abcdefghijklmnopqrstuvwxyz', number, 1)

    from dbo.Numbers

    where number between 1 and 26;

    select Col1

    from #T

    for XML path;

    select Col1

    from #T

    for XML path('');

    select ', ' + Col1

    from #T

    for XML path;

    select ', ' + Col1

    from #T

    for XML path('');

    You'll see that the comma gets rid of the Col1 header, and the ('') gets rid of the row header, so all you're left with is the value and the comma.

    Try some variations on it. Put an "a" in there instead of a comma, or a vertical-pipe instead of a comma. Basically, anything that would result in "(no column name)" if you ran it as a regular query will accomplish what the comma does there.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • Okay, so the concatenation of ', ' + Col1 results in the loss of the column name and the FOR XML PATH ('') replaces the . I think I understand a little better what is going on with it now. Thanks!

  • You're welcome.

    - Gus "GSquared", RSVP, OODA, MAP, NMVP, FAQ, SAT, SQL, DNA, RNA, UOI, IOU, AM, PM, AD, BC, BCE, USA, UN, CF, ROFL, LOL, ETC
    Property of The Thread

    "Nobody knows the age of the human race, but everyone agrees it's old enough to know better." - Anon

  • Hey, I think I almost understand it now. It's an xml doc without tags and since the XML is returned in one column you now have a delimited list.

    Makes since when you think about it and see some results.

  • Gus already explained the STUFF trick to take away the leading comma, so I will try to explain the XML PATH trick. Not because I am an XML Guru, but rather because I just recently spent some considerable time trying to understand it myself:

    The SELECT...FOR XML PATH feature is intended to allow you to easily build XML. The basic application on our sample data (from Lynn's example) would be:

    Select ColB

    From @TestTab

    For XML PATHWhich produces:

    [font="Courier New"]<row>

      <ColB>John</ColB>

    </row>

    <row>

      <ColB>Josh</ColB>

    </row>

    <row>

      <ColB>Bob</ColB>

    </row>

    <row>

      <ColB>Kathy</ColB>

    </row>

    <row>

      <ColB>Jill</ColB>

    </row>

    [/font]

    Now this does technically concatenate our strings together, however, you will notice two problems with it:

    1) the {row} tags, and

    2) the {ColB} tags

    (the line breaks and indentations were added by me for easy reading).

    The {row} tags are intended to reflect the source table's name, but they can be overridden by the PATH argument. Using PATH('TableVar') would give us {TableVar} tags instead. As it happens a specific feature of FOR XML PATH is that if you use an explicitly empty name: PATH(''), instead of giving us empty row tags ({}...{/}) which would be invalid XML, it removes the row tags altogether. So:

    Select ColB

    From @TestTab

    For XML PATH('')

    This gives us the following:

    [font="Courier New"]<ColB>John</ColB><ColB>Josh</ColB><ColB>Bob</ColB><ColB>Kathy</ColB><ColB>Jill</ColB>[/font]

    So we still have the column tags to deal with.

    Now it is clear the the column tags are coming from the column name, so you might think that all we have to do is give the column a blank name and the column tags will disappear also. And yes, that is true, but that is harder than it sounds because there is no way to explicitly give a column a blank name.

    For instance, "SELECT ColB as [] From @TestTab" is invalid syntax. However, it turns out that there is an implicit way to do this: output columns that are expressions have no column name unless you explicitly give them one.

    Thus, we can eliminate our column names by using some null operation on our column, like so:Select ''+ ColB

    From @TestTab

    For XML PATH('')which gives us:

    JohnJoshBobKathyJill

    Now all that's left is to add in the comma separator. In a happy coincidence, this merges perfectly with the previous trick, like so:Select ','+ ColB

    From @TestTab

    For XML PATH('')which finally gives us:

    ,John,Josh,Bob,Kathy,Jill

    And this takes us back to the STUFF trick to get rid of the leading comma, as explained by Gus.

    (edit: typos)

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

  • Dang it! I hate how slow I am on posts... :angry:

    [font="Times New Roman"]-- RBarryYoung[/font], [font="Times New Roman"] (302)375-0451[/font] blog: MovingSQL.com, Twitter: @RBarryYoung[font="Arial Black"]
    Proactive Performance Solutions, Inc.
    [/font]
    [font="Verdana"] "Performance is our middle name."[/font]

Viewing 15 posts - 1 through 15 (of 30 total)

You must be logged in to reply to this topic. Login to reply