我想说我想要一张包含以下列和值的表格:
| BucketID | Value |
|:-----------|------------:|
| 1 | 3 |
| 1 | 2 |
| 1 | 1 |
| 2 | 0 |
| 2 | 1 |
| 2 | 5 |
让我假装我想要对BucketId进行分区并将分区中的值相乘:
SELECT DISTINCT BucketId, MULT(Value) OVER (PARTITION BY BucketId)
现在,没有内置的Aggregate MULT函数,所以我使用SQL CLR编写自己的函数:
using System;
using System.Data.SqlTypes;
using Microsoft.SqlServer.Server;
[Serializable]
[SqlUserDefinedAggregate(Format.Native, Name = "MULT")]
public struct MULT
{
private int runningSum;
public void Init()
{
runningSum = 1;
}
public void Accumulate(SqlInt32 value)
{
runnningSum *= (int)value;
}
public void Merge(OverallStatus other)
{
runnningSum *= other.runningSum;
}
public SqlInt32 Terminate()
{
return new SqlInt32(runningSum);
}
}
我的问题归结为,让我们假设我在Accumulate
或Merge
中遇到0,没有必要继续下去。如果是这种情况,我怎么能在0到0时返回0?
答案 0 :(得分:1)
您无法强制终止,因为无法控制工作流程。当每个组完成处理其集合时,SQL Server将调用Terminate()
方法。
但是,由于在组中处理的每一行中都维护了UDA的状态,因此您只需检查runningSum
以查看它是否已经0
,如果是,则跳过任何计算。这样可以节省一些时间。
在Accumulate()
方法中,第一步是检查runningSum
是否为0
,如果为真,则只需return;
。您还应该检查value
是否为NULL
(您当前未检查的内容)。之后,检查传入的value
是否为0
,如果为真,则将runningSum
设置为0
和return;
。
public void Accumulate(SqlInt32 value)
{
if (runningSum == 0 || value.IsNull)
{
return;
}
if (value.Value == 0)
{
runningSum = 0;
return;
}
runningSum *= value.Value;
}
注意:请勿将value
投射到int
。所有Sql*
类型都具有Value
属性,该属性返回预期的本机.NET类型。
最后,在Merge
方法中,选中runnningSum
以查看它是0
还是f,只需return;
。然后检查other.runningSum
以查看它是否为0
,如果为真,则将runnningSum
设置为0
。