O que eu tenho é um CLR SqlFunction
que produz 3 arrays de doubles. Eu gostaria que esta função retornasse algo apropriado para que eu FillRowMethod
pudesse produzi-la para mim como uma tabela em T-SQL. Funciona bem para 1 array, mas estou tendo problemas para estendê-lo para vários. Estou principalmente inseguro sobre o que retornar do meu método. Algum código abaixo:
[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
}
EDITAR:
Com base no feedback, esta é a minha nova tentativa de solução.
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);
}
Se você deseja retornar as 3 matrizes como 3 conjuntos de resultados separados, isso não é possível para uma função, seja SQLCLR ou T-SQL. Em vez disso, você precisaria criar um procedimento armazenado para retornar vários conjuntos de resultados.
Se os 3 arrays representarem 3 colunas de um único conjunto de resultados de forma que todos tenham o mesmo número de itens e o valor de índice de um esteja conceitualmente associado ao mesmo valor de índice dos outros (ou seja ,
array1[x]
está associado aarray2[x]
earray3[x]
, enquantoarray1[y]
está associado comarray2[y]
earray3[y]
, e assim por diante), uma matriz simples é o tipo errado de coleção. Você só pode retornar uma única coleção em que cada item/elemento na coleção representa uma linha no conjunto de resultados (ou pelo menos informações suficientes para construir a linha desejada). Essa coleção singular, quando retornada doSqlFunction
método, é iterada, chamando oFillRowMethod
para cada item/elemento. Um item/elemento é passado para oFillRowMethod
que constrói a estrutura e os valores do conjunto de resultados finais e os devolve (portanto, você tem a oportunidade de criar e/ou traduzir valores do item original antes de devolvê-los).Neste último caso, você precisaria criar uma classe semelhante a:
Em seguida, crie uma lista genérica daqueles em seu
getStrippedCapletVolatilitiesFromCapVolatilityCurve
método, adicione um novo item a essa coleção para cada linha a ser retornada e, em seguida, retorne essa lista/coleção. SeuFillRowMethod
será chamado com o primeiro parâmetro (asobject
) sendo do tipovolatility
. É aí que você preencherá osout
parâmetros dessas propriedades devolatility
. Por exemplo:Agora, pode ser possível lidar com isso como um array bidimensional (ou seja,
double[][]
) que você retorna do mainSqlFunction
, mas oFillRow
método seria enviado adouble[]
já que a primeira dimensão é dividida em chamadas individuais para oFillRow
método. Eu nunca tentei essa abordagem específica, mas deve funcionar da seguinte forma:TAMBÉM:
Acabou de me ocorrer que você poderia até mesmo renunciar à lista/coleção genérica e transmitir o conteúdo da
double[][]
matriz para o conjunto de resultados, um item/linha de cada vez. Vá em frente e tente isso:Existem algumas restrições ao usar
yield return
, mas se o seu processo permitir essa construção, isso não apenas será mais rápido, mas também ocupará menos memória. Esses benefícios são devidos a esse código pular a etapa de copiar os resultados dogetCapletCurveForGivenStrike()
método para uma coleção separada (ou seja, a Lista Genérica) apenas para retorná-la ao T-SQL (nesse caso, você precisa esperar enquanto copia a coleção e consome mais memória).Em uma nota relacionada: use os
Sql*
tipos para os parâmetros de entrada em vez dos tipos .NET padrão. Ou seja, useSqlString
em vez destring
eSqlDouble
em vez dedouble
. Você pode facilmente obter o tipo nativo do .NET através daValue
propriedade que todos osSql*
tipos possuem (por exemplo ,SqlString.Value
retorna umstring
, etc).Para obter mais informações sobre como trabalhar com SQLCLR em geral, visite: SQLCLR Info