襭 覃覈襴螳 豢覿る 螳 .
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<int, object> dict;
// Recreate the hash table for each new group
public void Init()
{
dict = new Dictionary<int, object>();
}
// 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<int, object>(recordCount);
for (var i = 0; i < recordCount; i++)
{
dict[r.ReadInt32()] = null;
}
}
}
願碓 VB.NET... 豢..豌襴 覩誤″螻.. 貊る(,) 蟇碁 伎 螻..
Imports System
Imports System.Data
Imports Microsoft.SqlServer.Server
Imports System.Data.SqlTypes
Imports System.IO
Imports System.Text
Imports System.Collections
<Serializable(), SqlUserDefinedAggregate(Format.UserDefined, IsInvariantToNulls:=True, IsInvariantToDuplicates:=False, IsInvariantToOrder:=False, MaxByteSize:=-1)> _
Public Class CountDistinct
Implements IBinarySerialize
''' <summary>
''' The variable that holds the intermediate result of the concatenation
''' </summary>
Private intermediateResult As StringBuilder
''' <summary>
''' Initialize the internal data structures
''' </summary>
Public Sub Init()
Me.intermediateResult = New StringBuilder()
End Sub
''' <summary>
''' Accumulate the next value, not if the value is null
''' </summary>
''' <param name="value"></param>
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
''' <summary>
''' Merge the partially computed aggregate with this aggregate.
''' </summary>
''' <param name="other"></param>
Public Sub Merge(ByVal other As CountDistinct)
Me.intermediateResult.Append(other.intermediateResult)
End Sub
''' <summary>
''' Called at the end of aggregation, to return the results of the aggregation.
''' </summary>
''' <returns></returns>
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