0

我已将用户定义的聚合添加到我的数据库中,用于计算组的乘积。

代码基本上是从这里逐字提取的逐字提取的。

我正在使用该函数来计算我拥有每月回报数据的金融工具的生命周期至今回报。该表如下所示:

----------------------------------------------------------
| InstrumentId(int) | MonthEnd(datetime) | Return(float) |
----------------------------------------------------------

我的查询如下所示:

SELECT R1.InstrumentId,
       R1.MonthEnd,
       R1.MonthlyReturn,
       dbo.Product(1 + R2.MonthlyReturn) AS TotalReturn
FROM Returns R1
INNER JOIN Returns R2 ON  R2.InstrumentId = R1.InstrumentId 
                      AND R2.MonthEnd <= R1.MonthEnd
WHERE R1.InstrumentId BETWEEN 1 AND 50
GROUP BY R1.InstrumentId, R1.MonthEnd, R1.MonthlyReturn
ORDER BY R1.InstrumentId, R1.MonthEnd

当我只有几个仪器时,查询工作正常,但添加某些仪器会导致每个结果都为 NULL。当我使用 OPTION(MAXDOP 1) 执行查询时,结果很好。

有谁知道是什么导致了这个问题?

编辑:忘了提到我正在运行 SQL Server 2012 和聚合目标 .NET 4.5

4

2 回答 2

1

NULL如果我希望它忽略s ,这些是我将对 Product 聚合进行的修改。

更改属性:

[Microsoft.SqlServer.Server.SqlUserDefinedAggregate(
   Microsoft.SqlServer.Server.Format.Native,
   IsInvariantToDuplicates = false,
   IsInvariantToNulls = true,      // receiving a NULL value will be ignored
   IsInvariantToOrder = true,
   IsNullIfEmpty = true,
   Name = "Product"
)]

改变Accumulate

 public void Accumulate(System.Data.SqlTypes.SqlDouble number) {
  if (!this.HasValue && !number.IsNull) { //Don't know if we'll be passed a NULL, but protect ourselves nonetheless
     this.Result = number;
  } else if (number.IsNull) {
     return; //Avoid setting HasValue
  } else {
     this.Result = System.Data.SqlTypes.SqlDouble.Multiply(this.Result, number);
  }
  this.HasValue = true;
}

改变Merge

public void Merge(Product group) {
  if (group.HasValue) {
    if(this.HasValue) {
     this.Result = System.Data.SqlTypes.SqlDouble.Multiply
            (this.Result, group.Result);
    } else { //We may never have had our own value set
     this.Result = group.Result;
     this.HasValue = true;
    }
  }
}

我不确定是否Merge真的需要更改为,但为了安全起见,我会这样做。

于 2013-07-11T07:09:16.950 回答
0

如果1 + R2.MonthlyReturn是肯定的,我会考虑使用exp(sum(log(...)))等价物:

SELECT R1.InstrumentId,
       R1.MonthEnd,
       R1.MonthlyReturn,
       EXP(SUM(LOG(1 + R2.MonthlyReturn))) AS TotalReturn
FROM Returns R1
INNER JOIN Returns R2 ON  R2.InstrumentId = R1.InstrumentId 
                      AND R2.MonthEnd <= R1.MonthEnd
WHERE R1.InstrumentId BETWEEN 1 AND 50
GROUP BY R1.InstrumentId, R1.MonthEnd, R1.MonthlyReturn
ORDER BY R1.InstrumentId, R1.MonthEnd
于 2013-07-10T14:36:14.640 回答