SQL Server 2008 CLR 聚合函数
Posted
技术标签:
【中文标题】SQL Server 2008 CLR 聚合函数【英文标题】:SQL Server 2008 CLR aggregate function 【发布时间】:2014-01-27 13:29:06 【问题描述】:我一直在研究使用 CLR 聚合对一系列数据执行一些复杂的财务计算,但是尽管阅读了很多关于该主题的文章并且进行了很多摆弄,但我还是无法弄清楚。
我的输入是一系列日期和值,我希望能够执行以下操作:
SELECT dbo.FinancialCalc(amount, date)
FROM (VALUES
(-100000, '11/30/2011'),
(-50000, '3/15/2012'),
(-2500, '7/18/2012')
) n(amount, date)
到目前为止,这是我的代码:
[SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize = 8000, Name = "FinancialCalc", IsInvariantToDuplicates = false, IsInvariantToNulls = true, IsInvariantToOrder = true, IsNullIfEmpty = true)]
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public class FinancialCalc : IBinarySerialize
private List<Transaction> transactions;
private List<DateTime> dates;
private List<Double> values;
public void Init()
this.transactions = new List<Transaction>();
this.dates = new List<DateTime>();
this.values = new List<double>();
public void Accumulate(SqlDouble amount, SqlDateTime date)
this.dates.Add(date.Value);
this.values.Add(amount.Value);
public void Merge(FinancialCalc Group)
//is this needed?
public SqlDouble Terminate()
//here is where I would do the calc: return transactions.Calculate() or somethine
return values.Sum();
public void Read(System.IO.BinaryReader r)
int itemCount = r.ReadInt16();
for (int i = 0; i <= itemCount - 1; i++)
this.values.Add(r.ReadDouble());
public void Write(System.IO.BinaryWriter w)
w.Write(this.values.Count);
foreach (double s in this.values)
w.Write(s);
如何将SQL查询中的数据成功拿到List<Transaction>
中,以便处理并返回计算值?
【问题讨论】:
您是否需要日期和值的列表,或者这正是您目前所拥有的?您想要的只是Transaction
对象的(任意)列表吗? Transaction
对象是什么样的?
其他列表只是为了测试——交易就是我所需要的。交易看起来像public class Transaction public double value get;set; public DateTime date get;set;
所以,类似于我的回答中假设的一个。所有需要改变的(如果你不想改变你的Transaction
定义以匹配我的)是使用对象初始化语法而不是我假设的构造函数,在Accumulate
和Read
。跨度>
【参考方案1】:
如果我假设 Transaction
看起来像这样:
public class Transaction
private readonly double _amount;
private readonly DateTime _date;
public Transaction(double amount,DateTime date)
_amount = amount;
_date = date;
public double Amount getreturn _amount;
public DateTime Date getreturn _date;
然后我假设你真正想要的看起来像这样:
[SqlUserDefinedAggregate(Format.UserDefined,
//Play it safe, we don't know how large we'll get
MaxByteSize = -1,
Name = "FinancialCalc", IsInvariantToDuplicates = false,
IsInvariantToNulls = true, IsInvariantToOrder = true,
IsNullIfEmpty = true)]
[Serializable]
[StructLayout(LayoutKind.Sequential)]
public class FinancialCalc : IBinarySerialize
private List<Transaction> transactions;
public void Init()
this.transactions = new List<Transaction>();
public void Accumulate(SqlDouble amount, SqlDateTime date)
this.transactions.Add(new Transaction(date.Value,amount.Value));
public void Merge(FinancialCalc Group)
//Yes, you do need this. Group contains another set of transactions
//and is going to disappear after this method has been called
this.transactions.AddRange(Group.transactions);
public SqlDouble Terminate()
//Do your calculation based on the content of transactions
return new SqlDouble(transactions.Sum(t=>t.Amount));
public void Read(System.IO.BinaryReader r)
int itemCount = r.ReadInt16();
for (int i = 0; i <= itemCount - 1; i++)
this.transactions.Add(new Transaction(r.ReadDouble(),
new DateTime(r.ReadInt64()));
public void Write(System.IO.BinaryWriter w)
w.Write(this.transactions.Count);
foreach (var t in this.transactions)
w.Write(t.Amount);
w.Write(t.Date.ToBinary());
【讨论】:
感谢@Damien,非常感谢。虽然在部署时出现错误 - `CREATE AGGREGATE 失败,因为类型 'FinancialCalc' 由于字段 'CS$9__CachedAnonymousMethodDelegate1' 不符合 UDAGG 规范。我认为这是因为终止方法中的 LINQ,它反正我也不需要。 @woggles - 是的,我只是手工编写的,我没有尝试编译它或将它添加到 SQL Server 实例中:-( 差不多了 :) 转换日期时的另一个问题我认为:System.ArgumentOutOfRangeException: Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. Parameter name: ticks
运行 sql 时
@woggles,您是否尝试使用dateTimeValue = sqlDateTimeValue.Value
以外的转换方法?以上是关于SQL Server 2008 CLR 聚合函数的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 中系统视图sysobjects中type字段的说明