Selecting a Comma Delimited List with TSQL

Sometimes instead of bringing back a table set of information, a query needs to return a comma delimited list.  I have seen some crazy stuff to do this like UDFs and Cursors.  There is a really simple way to do this in a select statement though.

--declare a variable first
DECLARE @Orders varchar(MAX)

--varchar max is nice because there won't be overflow if the table is large
SET @Orders = '' --we can't concatenate NULLs so make empty string

SELECT @Orders = @Orders + Convert(varchar(10),Orders) + ','
FROM dbo.Orders

PRINT Left(@Orders,Len(@Orders)-1) --remove last comma

 

What did you think of this article?




Trackbacks
  • No trackbacks exist for this entry.
Comments
Page: 1 of 1
  • 12/11/2007 Lathangi wrote:
    Hi,
    Can we write the same query without using variable.
    Reply to this
    1. 12/17/2007 Adam Rink wrote:
      You could select the variable like SELECT @Orders as a second query in the proc.

      You would have to do some kind of loop statement or a cursor.





      Reply to this
      1. 12/17/2007 Lathangi wrote:
        Hi Adam Rink,

        Need help on this.

        Say,I have a table with two columns and with following data,

        Col1 col2
        -----------------
        1 John
        2 Jill
        1 Smith
        1 Jack
        2 Smack
        Now my query should return the values in the following way..

        Col1 Col2
        -------------------
        1 John;Smith;Jack;
        2 Jill;Smack;

        I need help on this..its very urgent.. I tried using Userdefined functions, but its taking about 4-5 min
        Reply to this
        1. 12/18/2007 Adam Rink wrote:
          Good one, I'm racking my brain on it.  I hate using cursors but this might be a case where need to.  I'm not sure your record count or the performance of this, but it will work.  I'll keep thinking on this one though.

          DECLARE @temp table (col1 int, col2 varchar(MAX))
          DECLARE @tempNames table (col1 int, col2 varchar(MAX))

          INSERT INTO @tempNames (col1, col2) VALUES (1,'John')
          INSERT INTO @tempNames (col1, col2) VALUES (2,'Jill')
          INSERT INTO @tempNames (col1, col2) VALUES (1,'Smith')
          INSERT INTO @tempNames (col1, col2) VALUES (1,'Jack')
          INSERT INTO @tempNames (col1, col2) VALUES (2,'Smack')

          INSERT INTO @temp (col1)
          SELECT Distinct col1
          FROM @tempNames

          DECLARE @curCol int
          DECLARE @commaList varchar(MAX)


          DECLARE myCursor CURSOR
              FOR SELECT DISTINCT col1
                      FROM @tempNames

          OPEN myCursor
          FETCH NEXT FROM myCursor INTO @curCol

          WHILE @@FETCH_STATUS = 0
          BEGIN
              SET @commaList = ''
              SELECT @commaList = @commaList + col2 + ','
              FROM @tempNames
              WHERE col1 = @curCol

              UPDATE @temp
              SET col2 = Left(@commaList,Len(@commaList)-1)
              WHERE col1 = @curCol

              FETCH NEXT FROM myCursor INTO @curCol
          END

          SELECT * FROM @temp

          CLOSE myCursor
          DEALLOCATE myCursor
          Reply to this
  • 12/18/2007 Lathangi wrote:
    CREATE TABLE #temp (SNo int identity ,empno varchar(20) not null,Domain_Name varchar(500))
    CREATE TABLE #temp1 (Cnt int identity ,empno varchar(20) not null)
    CREATE TABLE #GetEmpDomains (empno varchar(20) not null,Domain_Name varchar(2500))

    insert into #temp(empno ,Domain_Name)
    select distinct empno,Domain_Name from
    Azviw_Sms

    insert into #temp1(empno)
    SELECT DISTINCT empno from emp_mstr

    declare @vcnt int
    declare @vloopcnt int
    declare @vid int
    declare @vtmpid int
    declare @vdomains VARCHAr(50)
    declare @vtmp1cnt INT
    declare @vSecondLoopCnt int
    declare @vSecondtblCnt int
    declare @MainID varchar(20)
    declare @vCurrentDomain varchar(50)

    SET @vloopcnt = 1
    SET @vSecondLoopCnt = 1

    set @vcnt = (select count(*) from #temp)
    SET @vtmp1cnt = (SELECT COUNT(*) FROM #temp1)

    while(@vloopcnt <= @vtmp1cnt)
    BEGIN

    SELECT @MainID = empno FROM #temp1 WHERE Cnt = @vloopcnt
    SELECT @vSecondtblCnt = COUNT(*) FROM #temp WHERE empno = @MainID

    WHILE(@vSecondLoopCnt <= @vSecondtblCnt)
    BEGIN
    SET @vCurrentDomain = (SELECT TOP 1 Domain_Name FROM #temp WHERE empno = @MainID)

    DELETE FROM #temp WHERE Domain_Name = @vCurrentDomain and empno = @MainID
    SET @vdomains = ISNULL(@vdomains,'') + @vCurrentDomain + '; '

    SET @vSecondLoopCnt = @vSecondLoopCnt + 1
    END

    INSERT INTO #GetEmpDomains (empno,Domain_Name)
    SELECT @MainID,@vdomains

    SET @vloopcnt = @vloopcnt + 1
    SET @vSecondLoopCnt = 1
    SET @vdomains = ''

    END

    select * from #GetEmpDomains

    drop TABLE #temp
    drop TABLE #temp1
    drop TABLE #GetEmpDomains
    Reply to this
    1. 12/18/2007 Lathangi wrote:
      As you can see in my previous query, my table contains about 5000 records.
      And by using above query its taking about 10-13 seconds. for time being i can manage the things with the above query. but i came to know, without using temp tables and variables or cursors we can't acheive it.
      Reply to this
      1. 12/18/2007 Adam Rink wrote:
        You aren't going to get away from the variable or temp tables. 

        If you are worried about performance, I would suggest replacing the inner while loop with the variable select list in this case.  It will cut down the scans.  Other than that if you are using .Net or something to display the data, you might be able to use the SPLIT function.

        SELECT @MainID = empno FROM #temp1 WHERE Cnt = @vloopcnt
        SELECT @vSecondtblCnt = COUNT(*) FROM #temp WHERE empno = @MainID

        WHILE(@vSecondLoopCnt <= @vSecondtblCnt)
        BEGIN
        SET @vCurrentDomain = (SELECT TOP 1 Domain_Name FROM #temp WHERE empno = @MainID)

        DELETE FROM #temp WHERE Domain_Name = @vCurrentDomain and empno = @MainID
        SET @vdomains = ISNULL(@vdomains,'') + @vCurrentDomain + '; '

        SET @vSecondLoopCnt = @vSecondLoopCnt + 1
        END

        with

        SELECT @MainID = empno FROM #temp1 WHERE Cnt = @vloopcnt

        SELECT @vdomains= @vdomains + Domain_Name + ';'
            FROM #temp
            WHERE empno = @MainID


        DELETE FROM #temp WHERE Domain_Name = @vCurrentDomain and empno = @MainID

        Reply to this
        1. 12/18/2007 Lathangi wrote:
          Hi Adam Rink,
          Thank you so much. It helped me.But there is some data mismatch. I am trying to find out that. Any ways thanks a lot for spending your valuable time on my query
          Thanks,
          Latha
          Reply to this
          1. 12/19/2007 Adam Rink wrote:
            It could be
            DELETE FROM #temp WHERE Domain_Name = @vCurrentDomain and empno = @MainID

            It should be
            DELETE FROM #temp WHERE empno = @MainID

            Because the select takes all the domain names with that MainID above and puts it into a list.  Therefore we want to delete all the domains with that MainID. 

            Not sure if that is tripping you up.



            Reply to this
            1. 12/19/2007 Lathangi wrote:
              Thanks Adam Rink. Its working now
              Thanks for responding to my queries.

              Regards,
              Lathangi
              Reply to this

Page: 1 of 1
Leave a comment

 Enter the above security code (required)

 Name

 Email (will not be published)

 Website

Your comment is 0 characters limited to 3000 characters.