Problems
In this post I will discuss the aggregate function that concatenates strings. The article shows how to solve the problem and focuses on assembly function.
The example is shown on AdventureWorks 2008 database samples. The given problem is to assign products from table Production.Product to colors and show them in string separated by commas.
Input table:
SELECT color, name FROM AdventureWorks.Production.Product
Color Name
----------- ----------------------------------------
Black Chanling
Black Full Finger Gloves
...
Blue Classic Vest
Blue M Classic
...
...
Grey Touring Partners
(xx row(s) affected)
Expected result:
Color Product List
----------- --------------------------------------------------------------
Black Chanling, Full Finger Gloves , ...
Blue Classic Vest, M Classic, ...
Grey Touring Partners, ...
...
(xx row(s) affected)
XML PATH Method:
( SELECT name + ','
FROM AdventureWorks.Production.Product p2
WHERE p2.color = p1.color
ORDER BY name
FOR XML PATH('') ) AS Products
FROM AdventureWorks.Production.Product p1
GROUP BY p1.Color ;
Aggregation with assembly function – Common Language Runtime
Visual Studio dll project must be created. In SQL Server 2008 R2 required .NET version is 3.5 or lower.
CLR code:
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);
}
}
}
Compiled library must be imported to destination database. It can be done in Management Studio.
Next step is to create SQL aggregate function.
RETURNS nvarchar(8000)
EXTERNAL NAME [aggregate].[strconcat];
GO
After function is created, it can be used like build-in functions ie. with GROUP BY. The result set was limited because max varchar size is 8000.
dbo.String_aggregate(Name),
FROM AdventureWorks.Production.Product
WHERE listprice > 100
GROUP BY color

Hallo,
this works fine – thank you!
I also had to enable clr by using:
EXEC sp_configure ‘clr enabled’, 1;
RECONFIGURE WITH OVERRIDE;
GO
regards
tilman