using System; using System.IO; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; /* This defines the type WeightedValue which consists of two parts: one is a value and one is a weight. * This type is used for the weighted average aggregation function. */ [Serializable] [Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, MaxByteSize = 8000)] public class WeightedValue : INullable, IBinarySerialize { private bool isNull; private double value; private double weight; /* All user defined types for SQL require a constructor that takes no arguments */ public WeightedValue () { this.isNull = true; } /* However, other constructors are also useful */ public WeightedValue (SqlDouble val, SqlDouble wgt) { this.value = val.Value; this.weight = wgt.Value; this.isNull = false; } // WeightedValue() /* This defines the IsNull property of the class. * Note that "get" makes a variable act like a function. So, this is accessed * as whatever.IsNull rather than whatever.IsNull(). */ public bool IsNull { get { return isNull; } } // IsNull /* This returns a new instance of Weighted Average with a NULL value. */ public static WeightedValue Null { get { return new WeightedValue(); } } /* These are accessors for value and weight */ public double Value { get { return this.value; } } // Value public double Weight { get { return this.weight; } } // Weight /* Every SQL Type requires a ToString() function to convert the value to a string. * For this function, the string has the form "value=;weight=;" or * "". */ public override string ToString () { if (this.isNull) { return (""); } return "value=" + value.ToString("G") + ";weight=" + weight.ToString("G") + ";"; } // ToString() /* Parse is another required function. It needs to create a new WeightedValue from * a string representation, preferably the one created by ToString(). */ public static WeightedValue Parse (SqlString s) { if (s.IsNull || ("" == s)) { return (Null); } try { string[] values = s.Value.Split(';'); WeightedValue wv = new WeightedValue(); wv.isNull = false; for (int i = 0; i < values.GetLength(0); i++) { string[] parts = values[i].Split('='); switch (parts[0]) { case "value": wv.value = Double.Parse(parts[1]); break; case "weight": wv.weight = Double.Parse(parts[1]); break; } } return (wv); } catch (Exception ex) { throw new ArgumentException("The expected format is 'value=;weight='", ex); } } // Parse() /* Write() is another required function. This is the binary equivalent of ToString() */ public void Write (BinaryWriter w) { w.Write(this.isNull); if (! this.isNull) { w.Write(this.value); w.Write(this.weight); } } // Write() /* Read() is another required function. This is the binary equivalent of Parse(). */ public void Read (BinaryReader r) { this.isNull = r.ReadBoolean(); if (!this.isNull) { this.value = r.ReadDouble(); this.weight = r.ReadDouble(); } } // Read() } // WeightedValue /* This is the weighted value aggregation function. */ [Serializable] [SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToNulls = true, IsInvariantToDuplicates = false, IsInvariantToOrder = false, MaxByteSize = 8000)] public class WAvg : IBinarySerialize { private double sum; private double cnt; public void Init () { sum = 0; cnt = 0; } // Init() public void Accumulate (WeightedValue value) { if (!value.IsNull) { this.sum += value.Value * value.Weight; this.cnt += value.Weight; } } // Accumulate() public void Merge (WAvg group) { this.sum += group.sum; this.cnt += group.cnt; } // Merge() public SqlDouble Terminate () { return new SqlDouble(this.sum / this.cnt); } // Terminate() public void Read (BinaryReader r) { this.sum = r.ReadDouble(); this.cnt = r.ReadDouble(); } // Read() public void Write (BinaryWriter w) { w.Write(this.sum); w.Write(this.cnt); } // Write() } // Wavg public partial class UserDefinedFunctions { [Microsoft.SqlServer.Server.SqlFunction] public static WeightedValue CreateWeightedValue (SqlDouble val, SqlDouble wgt) { if (val.IsNull || wgt.IsNull) { return WeightedValue.Null; } return new WeightedValue(val, wgt); } // CreateWeightedValue() } // UserDefineFunctions