Search code examples
sql-server-2008t-sqlsql-server-2008-r2for-xml-path

Comma Delimited Result set + SQL Query


I got two tables with data as listed below:

Table1: Student

enter image description here

Table2: Subject

enter image description here

I need the output as:

enter image description here

I got this acheived with below query using for XML PATH

Code:

WITH    cte
      AS ( SELECT   Stu.Student_Id ,
                    Stu.Student_Name ,
                    ( SELECT    Sub.[Subject] + ','
                      FROM      [Subject] AS Sub
                      WHERE     Sub.Student_Id = Stu.Student_Id
                      ORDER BY  Sub.[Subject]
                    FOR
                      XML PATH('')
                    ) AS [Subjects]
           FROM     dbo.Student AS Stu
         )
SELECT  Student_id [Student Id] ,
        student_name [Student Name] ,
        SUBSTRING(Subjects, 1, ( LEN(Subjects) - 1 )) AS [Student Subjects]
FROM    cte

My question is there a better way to do this without using XML Path?


Solution

  • This is a very good approach and has become pretty well accepted. There are several approaches and this blog post describes a lot of them.

    One interesting approach that exists is using the CLR to do the work for you which will significantly reduce the complexity of the query with the trade-off of running external code. Here is a sample of what the class might look like in the assembly.

    using System;
    using System.Collections.Generic;
    using System.Data.SqlTypes;
    using System.IO;
    using Microsoft.SqlServer.Server;
    
    [Serializable]
    [SqlUserDefinedAggregate(Format.UserDefined,  MaxByteSize=8000)]
    public struct strconcat : IBinarySerialize{
    
        private List values;
    
        public void Init()    {
            this.values = new List();
        }
    
        public void Accumulate(SqlString value)    {
            this.values.Add(value.Value);
        }
    
        public void Merge(strconcat value)    {
            this.values.AddRange(value.values.ToArray());
        }
    
        public SqlString Terminate()    {
            return new SqlString(string.Join(", ", this.values.ToArray()));
        }
    
        public void Read(BinaryReader r)    {
            int itemCount = r.ReadInt32();
            this.values = new List(itemCount);
            for (int i = 0; i <= itemCount - 1; i++)    {
                this.values.Add(r.ReadString());
            }
        }
    
        public void Write(BinaryWriter w)    {
            w.Write(this.values.Count);
            foreach (string s in this.values)      {
                w.Write(s);
            }
        }
    }
    

    And that would net a query a bit more like this.

    SELECT CategoryId,
               dbo.strconcat(ProductName)
          FROM Products
         GROUP BY CategoryId ;
    

    Which is quite a bit simpler obviously. Take it for what it's worth :)

    Good day!