Thursday, 21 September 2006

Custom aggregation in SQL Server 2005 with .net class (2)

In my previous post, I discussed how to aggregate detail records into comma separated string using cursor. From what I have observed, cursor has performance issues in a large table.

In Sql Server 2005, we can write our own class in any .net language. The fowllowing article discusses an approach that meets my needs very well. If we use SQL Server 2005 we should consider this approach.
The original URL is here:
http://www32.brinkster.com/srisamp/sqlArticles/article_44.htm

To make it easier to understand. I just copy the code from the article and show how to use it.
The Aggregation function is written is vb.net.


Imports System
Imports System.Data.Sql
Imports System.Data.SqlTypes
Imports System.Text
Imports System.Runtime.Serialization

_
IsInvariantToOrder:=False, IsNullIfEmpty:=True, MaxByteSize:=8000)> _
Public Class FormDelimitedString
Implements IBinarySerialize

' Variable to hold the return result
Private returnString As StringBuilder

Public Sub Init()
' Initialize the string builder. This method will be called for each
' group that is accumulated
returnString = New StringBuilder()
End Sub

Public Sub Accumulate(ByVal value As SqlString)
' Accumulate the value into the string builder. If the value is NULL
'do not do anything. This method is called for each row of data
If (value.IsNull) Then
Return
Else
returnString.Append(value.Value).Append(", ")
End If
End Sub

Public Sub Merge(ByVal value As FormDelimitedString)
' Merge the current instance with the other instance.
returnString.Append(value.returnString)
End Sub

Public Function Terminate() As SqlString
' Return the result if the string has some content
If (returnString.Length > 0) Then
Return New SqlString(returnString.ToString(0, returnString.Length - 2))
End If

' Return an empty string otherwise
Return New SqlString("")
End Function

Public Sub Read(ByVal r As System.IO.BinaryReader) Implements System.Data.Sql.IBinarySerialize.Read
returnString = New StringBuilder(r.ReadString())
End Sub

Public Sub Write(ByVal w As System.IO.BinaryWriter) Implements System.Data.Sql.IBinarySerialize.Write
w.Write(returnString.ToString())

End Sub
End Class


To use this class, the dll needs to be deployed to the Sql Server 2005. The following example shows how to use it:

SELECT
ph.PurchaseOrderID, [Items] = dbo.FormDelimitedString (p.ProductNumber)

FROM
Purchasing.PurchaseOrderHeader ph
INNER JOIN Purchasing.PurchaseOrderDetail pd ON ph.PurchaseOrderID = pd.PurchaseOrderID
INNER JOIN Production.Product p ON pd.ProductID = p.ProductID
WHERE
ph.PurchaseOrderID < 10
GROUP BY
ph.PurchaseOrderID


The result would look like:
PurchaseOrderID Items
1 Item1, Item2, Item3
2 Item2, Item4

No comments: