感谢您阅读此内容,
VS2010针对SQLServer2008企业,开发CLR Aggregate函数来计算MODE,该函数返回此错误:“第1行CREATE AGGREGATE失败 因为类型'CMode'不符合 因字段而导致UDAGG规范 'CS $<> 9__CachedAnonymousMethodDelegate1'“
此处产生错误:
int mode = list.GroupBy(n => n).
OrderByDescending(g => g.Count()).
Select(g => g.Key).FirstOrDefault();
这是完整的代码:
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.Text;
[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined , MaxByteSize = 8000)]
public struct CMode : IBinarySerialize
{
private List<int> list;
public void Init()
{
this.list = new List<int>();
}
public void Accumulate(SqlInt16 Value)
{
this.list.Add(Value.Value);
}
public void Merge(CMode Group)
{
this.list.AddRange(Group.list.ToArray());
}
public SqlDecimal Terminate()
{
SqlInt16 rtn = new SqlInt16();
int mode = list.GroupBy(n => n).
OrderByDescending(g => g.Count()).
Select(g => g.Key).FirstOrDefault();
rtn = (SqlInt16)mode;
return rtn;
}
//IBinarySerialize
public void Read(BinaryReader r)
{
int itemCount = r.ReadInt16();
this.list = new List<int>(itemCount);
for (int i = 0; i <= itemCount - 1; i++)
{
this.list.Add(r.ReadInt16());
}
}
//IBinarySerialize
public void Write(BinaryWriter w)
{
w.Write(this.list.Count);
foreach (Int16 s in this.list)
{
w.Write(s);
}
}
}
任何指导都将不胜感激!!
我能够在SQLCLR函数中运行所希望的代码,以验证我是否拥有所有授权,dll在那里等等。:
û
sing System.Data.SqlClient;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
using System.Linq.Expressions;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Linq;
public partial class UserDefinedFunctions
{
[Microsoft.SqlServer.Server.SqlFunction]
public static SqlInt16 SQLCLR2008MODE()
{
List<int> list;
list = new List<int>();
list.Add(7);
list.Add(1);
list.Add(2);
list.Add(2);
list.Add(3);
list.Add(3);
list.Add(4);
list.Add(4);
list.Add(5);
list.Add(5);
list.Add(6);
int mode = list.GroupBy(n => n).
OrderByDescending(g => g.Count()).
Select(g => g.Key).FirstOrDefault();
return (Int16)mode;
}
};
期待您的评论。
答案 0 :(得分:2)
试试这段代码。你的代码不起作用,因为编译器会将你的隐式Func委托重写为已编译的委托(我强烈建议使用反射器来检查你自己的眼睛)。这不会是坏事,因为它主要是出于性能原因(每次调用时都要避免编译)但不幸的是,这会创建一个不可序列化的字段,并且只能与SQL Server不兼容。为避免这种情况,您必须使用表达式并手动编译它们。我的实现只在整个调用(init)中创建一次委托。
总而言之,我强烈建议使用HashSet集合实现模式,使用某种分组或者甚至是SortedHashSet。
[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(Format.UserDefined, MaxByteSize = 8000, IsInvariantToOrder=true, IsNullIfEmpty=true, IsInvariantToNulls=true)]
public struct Mode : IBinarySerialize
{
public void Init()
{
placeholder = new List<int>(10000);
Expression<Func<int, int>> ass = p => p;
grouper = ass.Compile();
Expression<Func<IGrouping<int, int>,int>> ass2 = q => q.Count();
sorter = ass2.Compile();
}
public void Accumulate(SqlInt32 Value)
{
placeholder.Add(Value.Value);
}
public void Merge(Mode Group)
{
placeholder.AddRange(Group.placeholder);
}
public SqlInt32 Terminate()
{
SqlInt32 result = placeholder.GroupBy(grouper).OrderByDescending(sorter).FirstOrDefault().Key ?? null;
placeholder.Clear();
return result;
}
// This is a place-holder member field
private List<int> placeholder;
private Func <int, int> grouper;
private Func<IGrouping<int, int>, int> sorter;
//IBinarySerialize
public void Read(BinaryReader r)
{
int itemCount = r.ReadInt32();
this.placeholder = new List<int>(itemCount);
for (int i = 0; i <= itemCount - 1; i++)
{
this.placeholder.Add(r.ReadInt16());
}
}
//IBinarySerialize
public void Write(BinaryWriter w)
{
w.Write(this.placeholder.Count);
foreach (Int32 s in this.placeholder)
{
w.Write(s);
}
}
}
答案 1 :(得分:0)
为了计算模式,我决定用SQL编写代码。即使查询数百万行,它也会非常快。查询计算每天的模式。
那是:
select T_Values.Date batch_date, T_Values.value mode
from (select a.Date, b.value, COUNT(*) num_items
from T1 a, T2 b
where a.Batch = b.Batch
and b.Product_ref = 100
and b.Attribute_Id = 1052
group by a.Date, b.value)
T_Values,
(select c.Date, MAX(c.num_items) max_num_items
from
(
select a.Date, b.value, COUNT(*) num_items
from T1 a, T2 b
where a.Batch = b.Batch
and b.Product_ref = 100
group by a.Date, b.value
) c
group by c.Date
) T_Max
where T_Values.num_items = T_Max.max_num_items
and T_Values.Date = T_Max.Date
order by T_Values.Date
答案 2 :(得分:0)
非常感谢Luckyluke !!!!
我在执行代码时遇到了一些错误,这些错误值与空值有关。在这个过程的最后,我用SQL编写它,它可以非常快速地完成工作。根据您的回答,我尝试实施Mediam。它工作正常,但它有8000参数大小限制。任何有兴趣学习如何绕过该限制的人都可以访问Expert SQL 2005的第6章并实现字典以避免序列化。
使用System; 使用System.Data; 使用System.Data.SqlClient; 使用System.Data.SqlTypes; 使用Microsoft.SqlServer.Server; 使用System.Collections.Generic; 使用System.IO; 使用System.Linq; 使用System.Linq.Expressions;
[Serializable] [SqlUserDefinedAggregate(Format.UserDefined
, MaxByteSize = 8000, IsInvariantToDuplicates = false, IsInvariantToOrder = false)]
public struct CMedian :IBinarySerialize { private List<int> list; public void Init() { this.list = new List<int>(); } public void Accumulate(SqlInt16 Value) { this.list.Add(Value.Value); } public void Merge(CMedian Group) { this.list.AddRange(Group.list.ToArray()); } public static IQueryable<T> ApplyOrdering<T , U>(IQueryable<T>
查询,表达式表达式) { 表达&GT; exp =(表达式&gt;)表达式; return query.OrderBy(exp); }
public SqlDecimal Terminate() { decimal median; int halfIndex; int numberCount; IQueryable<int> myInts = list.AsQueryable<int>(); Expression<Func<int , int>> myExpression = i => i; var sortedNumbers = (ApplyOrdering<int , int>(myInts ,
myExpression));
numberCount = myInts.Count(); halfIndex = (numberCount + 1) / 2; if ((numberCount % 2) == 0) { halfIndex = (numberCount) / 2; median = ((list.ElementAt(halfIndex) +
list.ElementAt(halfIndex + 1))/ 2); } 其他 { halfIndex =(numberCount + 1)/ 2; median = list.ElementAt(halfIndex); } return(SqlDecimal)中位数; } // IBinarySerialize public void Read(BinaryReader r) { int itemCount = r.ReadInt16(); this.list = new List(itemCount); for(int i = 0; i&lt; = itemCount - 1; i ++) { this.list.Add(r.ReadInt16()); } } // IBinarySerialize public void Write(BinaryWriter w) { 尝试 { foreach(Int16 s in this.list) { w.Write(一个或多个); } } catch(例外e) { 抛出新的异常(“Longitud:”+ w.BaseStream.Length +“位置:”+ w.BaseStream.Position); }
} }
答案 3 :(得分:0)
我使用.NET 3.5在Visual Studio 2010中创建了两个用于计算IRR和NPV的UDA。他们在SQL 2012上运行和部署得很好。但是,当我尝试将它们部署到SQL 2008R2时,它们因可怕的“不符合UDAGG规范”错误而失败。我试图实施LuckyLuke的方法,但没有成功。在我从UDA类中删除所有lambda表达式和LINQ之后,我终于在SQL 2008R2上取得了成功。有趣的是,我仍然可以在我的UDA使用的类中使用这些语言元素。