Is it possible to use user defined aggregates (clr) with window functions (over) ?
Can't find the answer in the documentation: http://technet.microsoft.com/en-us/library/ms190678.aspx
Windowing Aggregate Functions. Aggregate functions can be used as window functions; that is, you can use the OVER clause with aggregate functions.
User-defined functions are routines that can take parameters, perform calculations or other actions, and return a result. Beginning with SQL Server 2005 (9. x), you can write user-defined functions in any Microsoft . NET Framework programming language, such as Microsoft Visual Basic . NET or Microsoft Visual C#.
Aggregate functions: we can use these functions to calculate various aggregations such as average, total # of rows, maximum or minimum values, or total sum within each window or partition.
But unlike regular aggregate functions, use of a window function does not cause rows to become grouped into a single output row — the rows retain their separate identities. Behind the scenes, the window function is able to access more than just the current row of the query result.
You're right that it's tricky to find anything in the documentation. But searching the Connect website, I managed to find this gem:
Today, you can use CLR aggregates with OVER clause and PARTITION BY just like regular aggregate functions. Once we have support for window functions...
Which was a response from Microsoft.
However, searching on the Connect site was what I did whilst I was waiting for my aged machine to create a new database project and create this aggregate:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;
[Serializable]
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined,MaxByteSize = 2000)]
public struct SqlAggregate1 : IBinarySerialize
{
private SqlString last;
public void Init()
{
// Ignore
}
public void Accumulate(SqlString Value)
{
last = Value;
}
public void Merge (SqlAggregate1 Group)
{
// Ignore
}
public SqlString Terminate ()
{
// Put your code here
return last;
}
public void Read(BinaryReader r)
{
last = new SqlString(r.ReadString());
}
public void Write(BinaryWriter w)
{
w.Write(last.ToString());
}
}
And then run this script:
select dbo.SqlAggregate1(Column2) OVER (PARTITION BY Column1)
from (select 1,'abc' union all select 1,'def' union all
select 2,'ghi' union all select 2,'jkl') as t(Column1,Column2)
Which produces:
------------
abc
abc
ghi
ghi
Which is a long way to say - you could have easily discovered the answer for yourself just by trying it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With