Osc*_*car 6 sql-server c# sql-clr set-returning-functions
我拥有的是一个SqlFunction生成 3 个双精度数组的CLR 。我希望这个函数返回一些适当的东西,以便FillRowMethod可以将它作为 T-SQL 中的表输出给我。它适用于 1 个数组,但我无法将其扩展到多个数组。我主要不确定从我的方法返回什么。下面的一些代码:
[SqlFunction(DataAccess = DataAccessKind.Read, FillRowMethodName = "FillRow",
TableDefinition = "impliedVol float, maturity float, strike float")]
public static IEnumerable getStrippedCapletVolatilitiesFromCapVolatilityCurve(
string uploadDate, double strike, double yearsForward, double intervalDuration,
string curve, string surface)
//Create 3 arrays of doubles
double[] array1;
double[] array2;
double[] array3;
return [???];
}
public static void FillRow(object obj,
out SqlDouble impliedVol, out SqlDouble maturity, out SqlDouble strike)
{
//impliedVol = (double)obj; //This is what I do if only returning one array
}
Run Code Online (Sandbox Code Playgroud)
编辑:
根据反馈,这是我新尝试的解决方案。
public static IEnumerable getStrippedCapletVolatilitiesFromCapVolatilityCurve(string uploadDate, double strike, double yearsForward, double intervalDuration, string curve, string surface)
{
//omitted code above this line.
CapletStipping thisCapletStripping = new CapletStipping(maturities, forwardRates, discountingRates, intervalDuration);
double[][] theseStrippedCapletVols = thisCapletStripping.getCapletCurveForGivenStrike(flatVols, strike);
List<capletVolatilityNode> capletVolatilitiesList = new List<capletVolatilityNode>(theseStrippedCapletVols[0].Length);
for (int i = 0; i < theseStrippedCapletVols[0].Length; i += 1)
{
capletVolatilityNode thisCapletVolatilityNode = new capletVolatilityNode(theseStrippedCapletVols[0][i], theseStrippedCapletVols[1][i], theseStrippedCapletVols[2][i]);
capletVolatilitiesList[i] = thisCapletVolatilityNode;
}
return capletVolatilitiesList; // theseStrippedCapletVols;
}
public class capletVolatilityNode
{
public double impliedVol;
public double maturity;
public double strike;
public capletVolatilityNode(double impliedVol_, double maturity_, double strike_)
{
impliedVol = impliedVol_;
maturity = maturity_;
strike = strike_;
}
}
public static void FillRow(Object obj, out SqlDouble impliedVol, out SqlDouble maturity, out SqlDouble strike)
{
capletVolatilityNode row = (capletVolatilityNode)obj;
impliedVol = Convert.ToDouble(row.impliedVol);
maturity = Convert.ToDouble(row.maturity);
strike = Convert.ToDouble(row.strike);
}
Run Code Online (Sandbox Code Playgroud)
如果您想将 3 个数组作为 3 个单独的结果集返回,这对于函数来说是不可能的,无论是 SQLCLR 还是 T-SQL。您需要创建一个存储过程才能返回多个结果集。
如果这 3 个数组表示单个结果集的 3 列,这样它们都将具有相同数量的项目,并且一个的索引值在概念上与其他数组的相同索引值array1[x]相关联(即与array2[x]和相关联array3[x],而array1[y]与用array2[y]和array3[y],等等),则一个简单的数组是错误类型的集合。您只能返回一个集合,其中集合中的每个项目/元素代表结果集中的一行(或至少有足够的信息来构造所需的行)。当从该SqlFunction方法返回时,该单一集合被迭代,FillRowMethod为每个项目/元素调用。一个项目/元素被传递到FillRowMethod 它构造最终结果集结构和值并将它们传回(因此您有机会在传回之前从原始项目创建和/或转换值)。
在后一种情况下,您需要创建一个类似于以下内容的类:
private class volatility
{
public double impliedVol;
public double maturity;
public double strike;
}
Run Code Online (Sandbox Code Playgroud)
然后,在您的getStrippedCapletVolatilitiesFromCapVolatilityCurve方法中创建一个通用列表,为要返回的每一行向该集合添加一个新项目,然后返回该列表/集合。您FillRowMethod将被调用,第一个参数 (as object) 的类型为volatility。这就是你将填充out从这些属性PARAMS volatility。例如:
private static void FillRow(object obj,
out SqlDouble impliedVol, out SqlDouble maturity, out SqlDouble strike)
{
volatility row = (volatility)obj;
impliedVol = new SqlDouble(row.impliedVol);
maturity = new SqlDouble(row.maturity);
strike = new SqlDouble(row.strike);
}
Run Code Online (Sandbox Code Playgroud)
现在,可以将其作为double[][]从 main 返回的二维数组(即)来处理SqlFunction,但随后该FillRow方法将被发送,double[]因为第一个维度被分解为对该FillRow方法的单独调用。我从未尝试过这种特定方法,但它应该如下工作:
private static void FillRow(object obj,
out SqlDouble impliedVol, out SqlDouble maturity, out SqlDouble strike)
{
double[] row = (double[])obj;
impliedVol = new SqlDouble(row[0]);
maturity = new SqlDouble(row[1]);
strike = new SqlDouble(row[2]);
}
Run Code Online (Sandbox Code Playgroud)
还:
我double[][]突然想到您甚至可以放弃通用列表/集合并将数组的内容流式传输到结果集,一次一个项目/一行。继续尝试这个:
public static IEnumerable getStrippedCapletVolatilitiesFromCapVolatilityCurve(...)
{
//omitted code above this line.
CapletStipping thisCapletStripping =
new CapletStipping(maturities, forwardRates, discountingRates, intervalDuration);
double[][] theseStrippedCapletVols =
thisCapletStripping.getCapletCurveForGivenStrike(flatVols, strike);
// THIS PART IS DIFFERENT -- begin
capletVolatilityNode thisCapletVolatilityNode = new capletVolatilityNode();
for (int i = 0; i < theseStrippedCapletVols[0].Length; i += 1)
{
thisCapletVolatilityNode.impliedVol = theseStrippedCapletVols[0][i];
thisCapletVolatilityNode.maturity = theseStrippedCapletVols[1][i];
thisCapletVolatilityNode.strike = theseStrippedCapletVols[2][i];
yield return thisCapletVolatilityNode; // return rows individually
}
return; // cannot return anything when using "yield return"
// THIS PART IS DIFFERENT -- end
}
private class capletVolatilityNode
{
public double impliedVol;
public double maturity;
public double strike;
}
Run Code Online (Sandbox Code Playgroud)
使用时有一些限制yield return,但如果您的进程允许这种构造,那么这不仅会更快,而且占用的内存也更少。这些好处是由于这段代码跳过了将getCapletCurveForGivenStrike()方法的结果复制到单独的集合(即泛型列表)的步骤,只是为了将其返回给 T-SQL(在这种情况下,您需要等待它复制集合并消耗更多内存)。
相关说明:使用Sql*输入参数的类型而不是标准的 .NET 类型。意思是,使用SqlString代替string和SqlDouble代替double。然后,您可以通过Value所有Sql*类型具有的属性(例如SqlString.Value传回 astring等)轻松地从这些类型中获取 .NET 本机类型。
有关使用 SQLCLR 的更多信息,请访问:SQLCLR 信息
| 归档时间: |
|
| 查看次数: |
287 次 |
| 最近记录: |