Imports System
Imports System.Data
Imports System.Data.SqlClient
Imports System.Data.SqlTypes
Imports Microsoft.SqlServer.Server
Imports System.Runtime.InteropServices
<StructLayout(LayoutKind.Sequential)> _
<Serializable(), SqlUserDefinedAggregate(Format.Native, _
IsInvariantToDuplicates:=False, _
IsInvariantToNulls:=True, _
IsInvariantToOrder:=True, _
IsNullIfEmpty:=True, _
Name:="WeightedAvg")> _
Public Class WeightedAvg
''' <summary>
''' The variable that holds the intermediate sum of all values multiplied by their weight
''' </summary>
Private sum As Long
''' <summary>
''' The variable that holds the intermediate sum of all weights
''' </summary>
Private count As Integer
''' <summary>
''' The variable that holds the intermediate sum of all weights
''' </summary>
Public Sub Init()
sum = 0
count = 0
End Sub
''' <summary>
''' Accumulate the next value, not if the value is null
''' </summary>
''' <param name="Value">Next value to be aggregated</param>
''' <param name="Weight">The weight of the value passed to Value parameter</param>
Public Sub Accumulate(ByVal Value As SqlInt32, ByVal Weight As SqlInt32)
If Not Value.IsNull AndAlso Not Weight.IsNull Then
sum += CType(Value, Long) * CType(Weight, Long)
count += CType(Weight, Integer)
End If
End Sub
''' <summary>
''' Merge the partially computed aggregate with this aggregate.
''' </summary>
''' <param name="Group">The other partial results to be merged</param>
Public Sub Merge(ByVal Group As WeightedAvg)
sum = Group.sum
count = Group.count
End Sub
''' <summary>
''' Called at the end of aggregation, to return the results of the aggregation.
''' </summary>
''' <returns>The weighted average of all inputed values</returns>
Public Function Terminate() As SqlInt32
If count > 0 Then
'' int value = (int)(sum / count);
'' return new SqlInt32(value);
Dim value As Integer = CType(sum / count, Integer)
Return New SqlInt32(value)
Else
Return SqlInt32.Null
End If
End Function
End Class