我在SQL 2005中有一个UDA,它一直生成以下错误。我猜这很可能是由于最大字节大小为8000的限制....有什么工作我可以用来解决这个问题吗?有关在2005年避免此限制的任何建议吗?我知道2008年假设已经取消了这些限制,但暂时无法升级。
A .NET Framework error occurred during execution of user-defined routine or aggregate "CommaListConcatenate":
System.Data.SqlTypes.SqlTypeException: The buffer is insufficient. Read or write operation failed.
System.Data.SqlTypes.SqlTypeException:
at System.Data.SqlTypes.SqlBytes.Write(Int64 offset, Byte[] buffer, Int32 offsetInBuffer, Int32 count)
at System.Data.SqlTypes.StreamOnSqlBytes.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.IO.BinaryWriter.Write(String value)
at TASQLCLR.CommaListConcatenate.Write(BinaryWriter w)
答案 0 :(得分:5)
对于SQL 2005,您可以通过使用分隔符将一个参数转换为多个参数来解决8000字节限制。我不需要自己详细介绍细节,但你可以在这里找到答案:http://www.mssqltips.com/tip.asp?tip=2043
对于SQL 2008,您需要将MaxByteSize作为-1传递。如果您尝试传递大于8000的数字,SQL将不允许您创建聚合,抱怨存在8000字节限制。如果你传入-1,它似乎解决了这个问题,并允许你创建聚合(我也测试了> 8000字节)。
错误是:
大小(100000) “Class.Concatenate”不在 有效范围。大小必须为-1或a 数字在1到8000之间。
这是VB.NET支持的工作类定义> SQL 2008中的8000字节。
<Serializable(), SqlUserDefinedAggregate(Format.UserDefined,
IsInvariantToNulls:=True,
IsInvariantToDuplicates:=False,
IsInvariantToOrder:=False, MaxByteSize:=-1)>
<System.Runtime.InteropServices.ComVisible(False)> _
Public Class Concatenate Implements IBinarySerialize
End Class
答案 1 :(得分:3)
下面的代码显示了如何计算SQLAggregate中一组十进制数的媒体。它解决了实现数据字典的大小参数限制问题。这个想法来自Expert SQL Express 2005。
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<Guid , List<String>> theLists = new SafeDictionary<Guid , List<String>>();
private List<String> theStrings;
//Make sure to use SqlChars if you use
//VS deployment!
public SqlString Terminate()
{
List<Decimal> ld = new List<Decimal>();
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<String>();
}
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);
}
}
}
您还需要像Expert 2005那样实现字典:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace SafeDictionary
{
public class SafeDictionary<K, V>
{
private readonly Dictionary<K, V> dict = new Dictionary<K,V>();
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();
}
}
}
}
字典必须部署在具有不安全代码授权的单独程序集中。这个想法是避免通过保留在内存数据结构字典中来序列化所有数字。我推荐Expert SQL 2005章节:
第6章■SQLCLR:架构和 设计考虑因素。
顺便说一句,这个解决方案对我不起作用。从Decimal到String的转换过多,反之亦然,在处理数百万行时会变慢,无论如何,我很乐意尝试它。对于其他用途,这是一个很好的模式。