In this post we will learn how to implement UDF CLR Aggregates ,
In order to implement CLR UDF aggegate assembly we need to follow set of rules or requirements in technical terms, if any of rules are broken then it is not a valid
- Like any other CLR assembles in SQL Server, a CLR UDF Aggregate should have a attribute called SqlUserDefinedAggregat
In order to save the Intermediate state of Aggregation we use Four methods in the Aggregation
Syntax : public void Init();
Once this method is invoked the Query processor Initializes the aggregation , for every aggregation we need to invoke this method.
Syntax: public void Accumulate ( input-type value[, input-type value, …]);
Input type is any managed sql server data types
This where actual data aggregation occurs , it may be summing or multiplying , counting.
This method can be used to merge another instance of this aggregate class with the current instance. The query processor uses this method to merge multiple partial computations of an aggregation.
public return_type Terminate();
This method completes the aggregate computation and returns the result of the aggregation. The return_type should be a managed SQL Server data type.
The basic aggregate also has four attributes which are described in Andy Novak’s article.
||This is a compulsory enum with options Native, Unknown and UserDefined.
||Setting this to true tells the aggregate that it doesn’t care whether or not values are null or not, it will always produce the same result.
An example of an aggregate where the value for this is false is COUNT(field) which only counts instances that are NOT NULL
||Setting this to true tells the aggregate that it will produce the same results even if there are duplicate entries.
MAX() is a good example of this as no matter how many duplicates there are the MAX value will still be the MAX value.
||Setting this to true affects how SQL Server calls the Merge method of the aggregate.
If you had a string concatenation aggregate that was parallelised then it is vitally important that the streams merge back together in the correct order.
public struct CountVowels
// count only the vowels in the passed-in strings
private SqlInt32 countOfVowels;
public void Init()
countOfVowels = 0;
public void Accumulate(SqlString value)
// list of vowels to look for
string vowels = "aeiou";
// for each character in the given parameter
for (int i=0; i < value.ToString().Length; i++)
// for each character in the vowels string
for (int j=0; j < vowels.Length; j++)
// convert parameter character to lowercase and compare to vowel
if (value.Value.Substring(i,1).ToLower() == vowels.Substring(j,1))
// it is a vowel, increment the count
public void Merge(CountVowels value)
public SqlString Terminate()
After deploying the aggregate, test it by executing it on the SQL Server and verifying the correct data is returned.
This query returns a result set of the vowel count for all the values in the LastNames column in the Contact table.
SELECT LastName, COUNT(LastName) AS CountOfLastName, dbo.CountVowels(LastName) AS CountOfVowels
GROUP BY LastName
ORDER BY LastName