Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use user defined aggregates (clr) with window functions (over)?

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

like image 916
Roman Pokrovskij Avatar asked Mar 12 '14 12:03

Roman Pokrovskij


People also ask

Can I use an aggregate function with a window function?

Windowing Aggregate Functions. Aggregate functions can be used as window functions; that is, you can use the OVER clause with aggregate functions.

What is CLR User-Defined function?

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#.

What kind of aggregates do windowing functions calculate?

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.

What is the difference between window functions and aggregate functions?

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.


1 Answers

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.

like image 141
Damien_The_Unbeliever Avatar answered Oct 18 '22 08:10

Damien_The_Unbeliever