#title DistinctCount 이 솔루션은 메모리가 충분하다는 가정하에 써야 한다. http://sqlblog.com/blogs/paul_white/archive/2011/12/04/is-distinct-aggregation-still-considered-harmful.aspx 이거는 int형으로만 하는 꽁수다..대신 조낸 빠름.. {{{ using System; using System.Collections.Generic; using System.Data.SqlTypes; using System.IO; using Microsoft.SqlServer.Server; [SqlUserDefinedAggregate ( Format.UserDefined, IsInvariantToDuplicates = true, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = false, MaxByteSize = -1 ) ] public struct CountDistinctInt : IBinarySerialize { // The hash table private Dictionary dict; // Recreate the hash table for each new group public void Init() { dict = new Dictionary(); } // Ignore NULLs, store key values in the hash table public void Accumulate(SqlInt32 Data) { if (!Data.IsNull) { dict[Data.Value] = null; } } // Merge partial aggregates public void Merge(CountDistinctInt Group) { foreach (var item in Group.dict.Keys) { dict[item] = null; } } // Return the DISTINCT COUNT result public int Terminate() { return dict.Count; } // Required by SQL Server to serialize this object void IBinarySerialize.Write(BinaryWriter w) { w.Write(dict.Count); foreach (var item in dict.Keys) { w.Write(item); } } // Required by SQL Server to deserialize this object void IBinarySerialize.Read(BinaryReader r) { var recordCount = r.ReadInt32(); dict = new Dictionary(recordCount); for (var i = 0; i < recordCount; i++) { dict[r.ReadInt32()] = null; } } } }}} {{{ cd C:\Windows\Microsoft.NET\Framework64\v3.5 csc.exe /t:library "c:\clr\distinct_count.cs" copy distinct_count.dll c:\clr\ }}} {{{ drop aggregate distinct_count drop assembly distinct_count create assembly distinct_count from 'c:\clr\distinct_count.dll' go create aggregate distinct_count (@input int) returns int external name distinct_count.CountDistinctInt }}} 이거는 VB.NET... 대충..널처리도 미흡하고.. 콤마(,)는 없는걸로 해야 하고.. {{{ Imports System Imports System.Data Imports Microsoft.SqlServer.Server Imports System.Data.SqlTypes Imports System.IO Imports System.Text Imports System.Collections _ Public Class CountDistinct Implements IBinarySerialize ''' ''' The variable that holds the intermediate result of the concatenation ''' Private intermediateResult As StringBuilder ''' ''' Initialize the internal data structures ''' Public Sub Init() Me.intermediateResult = New StringBuilder() End Sub ''' ''' Accumulate the next value, not if the value is null ''' ''' Public Sub Accumulate(ByVal value As SqlString) If value.IsNull Then '''Return value = "3$^!~||-09abr$$@45!" End If Me.intermediateResult.Append(value.Value).Append(","c) End Sub ''' ''' Merge the partially computed aggregate with this aggregate. ''' ''' Public Sub Merge(ByVal other As CountDistinct) Me.intermediateResult.Append(other.intermediateResult) End Sub ''' ''' Called at the end of aggregation, to return the results of the aggregation. ''' ''' Public Function Terminate() As SqlInt64 Dim output As String = String.Empty 'delete the trailing comma, if any If Not (Me.intermediateResult Is Nothing) AndAlso Me.intermediateResult.Length > 0 Then output = Me.intermediateResult.ToString(0, Me.intermediateResult.Length - 1) End If Dim words As String() = output.Split(New Char() {","c}) Dim word As String Dim i As Integer Dim dict As New Hashtable() i = 0 For Each word In words If (dict.ContainsKey(word) = 0 and word <> "3$^!~||-09abr$$@45!") dict.Add(word, i) i = i + 1 End If Next Return dict.Count End Function Public Sub Read(ByVal r As BinaryReader) Implements IBinarySerialize.Read intermediateResult = New StringBuilder(r.ReadString()) End Sub Public Sub Write(ByVal w As BinaryWriter) Implements IBinarySerialize.Write w.Write(Me.intermediateResult.ToString()) End Sub End Class }}} {{{ cd C:\Windows\Microsoft.NET\Framework64\v3.5 vbc.exe /t:library "c:\clr\distinct_count.vb" }}}