Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>The code below shows how to calculate the media of a set of decimal numbers within an SQLAggregate. It resolves the issue of size parameter limitation implementing a data dictionary. The idea is taken from Expert SQL Express 2005.</p> <pre><code>using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; using System.Collections.Generic; using System.IO; using System.Linq; using System.Linq.Expressions; using SafeDictionary; [Microsoft.SqlServer.Server.SqlUserDefinedAggregate( Format.UserDefined, MaxByteSize=16)] public struct CMedian2 : IBinarySerialize { readonly static SafeDictionary&lt;Guid , List&lt;String&gt;&gt; theLists = new SafeDictionary&lt;Guid , List&lt;String&gt;&gt;(); private List&lt;String&gt; theStrings; //Make sure to use SqlChars if you use //VS deployment! public SqlString Terminate() { List&lt;Decimal&gt; ld = new List&lt;Decimal&gt;(); foreach(String s in theStrings){ ld.Add(Convert.ToDecimal(s)); } Decimal median; Decimal tmp; int halfIndex; int numberCount; ld.Sort(); Decimal[] allvalues = ld.ToArray(); numberCount = allvalues.Count(); if ((numberCount % 2) == 0) { halfIndex = (numberCount) / 2; tmp = Decimal.Add(allvalues[halfIndex-1], allvalues[halfIndex]); median = Decimal.Divide(tmp,2); } else { halfIndex = (numberCount + 1) / 2; median = allvalues[halfIndex - 1]; tmp = 1; } return new SqlString(Convert.ToString(median)); } public void Init() { theStrings = new List&lt;String&gt;(); } public void Accumulate(SqlString Value) { if (!(Value.IsNull)) theStrings.Add(Value.Value); } public void Merge(CMedian2 Group) { foreach (String theString in Group.theStrings) this.theStrings.Add(theString); } public void Write(System.IO.BinaryWriter w) { Guid g = Guid.NewGuid(); try { //Add the local collection to the static dictionary theLists.Add(g, this.theStrings); //Persist the GUID w.Write(g.ToByteArray()); } catch { //Try to clean up in case of exception if (theLists.ContainsKey(g)) theLists.Remove(g); } } public void Read(System.IO.BinaryReader r) { //Get the GUID from the stream Guid g = new Guid(r.ReadBytes(16)); try { //Grab the collection of strings this.theStrings = theLists[g]; } finally { //Clean up theLists.Remove(g); } } } </code></pre> <p>you also need to implement the dictionary as Expert 2005 does:</p> <pre><code>using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace SafeDictionary { public class SafeDictionary&lt;K, V&gt; { private readonly Dictionary&lt;K, V&gt; dict = new Dictionary&lt;K,V&gt;(); private readonly ReaderWriterLock theLock = new ReaderWriterLock(); public void Add(K key, V value) { theLock.AcquireWriterLock(2000); try { dict.Add(key, value); } finally { theLock.ReleaseLock(); } } public V this[K key] { get { theLock.AcquireReaderLock(2000); try { return (this.dict[key]); } finally { theLock.ReleaseLock(); } } set { theLock.AcquireWriterLock(2000); try { dict[key] = value; } finally { theLock.ReleaseLock(); } } } public bool Remove(K key) { theLock.AcquireWriterLock(2000); try { return (dict.Remove(key)); } finally { theLock.ReleaseLock(); } } public bool ContainsKey(K key) { theLock.AcquireReaderLock(2000); try { return (dict.ContainsKey(key)); } finally { theLock.ReleaseLock(); } } } } </code></pre> <p>The dictionary must be deployed in a separate assembly with unsafe code grants. The idea is to avoid to serializate all the numbers by keeping in memory data structure dictionary. I recommend the Expert SQL 2005 chapter: </p> <blockquote> <p>CHAPTER 6 ■ SQLCLR: ARCHITECTURE AND DESIGN CONSIDERATIONS.</p> </blockquote> <p>By the way, this solution didn't work for me. Too many conversions from Decimal to String and viceversa make it slow when working with millions of rows, anyway, I enjoyed to try it. For other usages it is a good pattern.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload