【发布时间】:2011-07-05 05:49:32
【问题描述】:
我正在为 SQL Server 2008 编写一些自定义 .Net 扩展。其中一个是用户定义的聚合,它应该将一组十进制数字聚合为一个十进制值。
为了缩小我的问题范围,我使用了一个简单的 Const 聚合,它只返回一个常量十进制值。将此作为用户定义的聚合添加到 SQL Server 时,返回的值总是四舍五入:
SELECT dbo.Const(n, 2.5) from (select 1 n) x -- returns 3, not 2.5
我错过了什么?
代码如下:
using System;
using System.Data.SqlTypes;
using System.IO;
using Microsoft.SqlServer.Server;
using SqlServer.Clr.Extensions.Aggregates.Implementation;
[Serializable]
[SqlUserDefinedAggregate(Format.UserDefined,MaxByteSize = -1)]
public class Const : IBinarySerialize
{
private decimal _constValue;
public void Init() {}
public void Accumulate(SqlDecimal value, SqlDecimal constValue)
{
_constValue = constValue.Value;
}
public void Merge(Const value) {}
public SqlDecimal Terminate()
{
return new SqlDecimal(_constValue);
}
public void Read(BinaryReader r)
{
_constValue = r.ReadDecimal();
}
public void Write(BinaryWriter w)
{
w.Write(_constValue);
}
}
将此代码编译为名为@987654324@ 的程序集。以下脚本可用于将其添加到 SQL Server 并验证意外行为:
use [MyDb] -- replace with your db name
go
-- drop the Const aggregate if it exists
IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Const]'))
DROP AGGREGATE [Const]
GO
-- drop the assembly if it exists
IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name = N'SqlServer.Clr.Extensions' and is_user_defined = 1)
DROP ASSEMBLY [SqlServer.Clr.Extensions]
GO
-- import the assembly
CREATE ASSEMBLY [SqlServer.Clr.Extensions]
AUTHORIZATION [dbo]
FROM 'C:\Path\To\SqlServer.Clr.Extensions.dll'
WITH PERMISSION_SET = SAFE
GO
CREATE AGGREGATE [Const](@input decimal, @constValue decimal)
RETURNS decimal
EXTERNAL NAME [SqlServer.Clr.Extensions].[Const] -- put the Const class is in the global namespace
GO
SELECT dbo.Const(n, 2) from (select 1 n) x
SELECT dbo.Const(n, 2.5) from (select 1 n) x
【问题讨论】:
-
我认为您必须设置小数的精度。尝试在 CREATE AGGREGATE [Const](@input decimal, @constValue decimal) 中将 @constValue decimal 更改为 @constValue decimal(13,2)
-
@Verrigo 哦,我的,当然……也许你应该写下你的评论作为答案,这样我才能接受?
标签: sql-server clr user-defined-aggregate