如何在 C# SQLCLR 函式中將多個雙精度數組作為表返回
我所擁有的是一個
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 }
編輯:
根據回饋,這是我嘗試的新解決方案。
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); }
如果您想將 3 個數組作為 3 個單獨的結果集返回,那麼無論是 SQLCLR 還是 T-SQL,這對於函式都是不可能的。您需要創建一個儲存過程來返回多個結果集。
如果 3 個數組表示單個結果集的 3 列,則它們都將具有相同數量的項目*,並且*其中一個的索引值在概念上與其他的相同索引值相關聯(即
array1[x]
與array2[x]
and相關聯array3[x]
,而array1[y]
與和array2[y]
等array3[y]
),那麼簡單數組是錯誤的集合類型。您只能返回一個集合,其中集合中的每個項目/元素代表結果集中的一行(或至少有足夠的資訊來構造所需的行)。當從SqlFunction
方法返回時,該單一集合被迭代,呼叫FillRowMethod
為每個項目/元素呼叫。一項/元素被傳遞到FillRowMethod
它構造最終的結果集結構和值並將它們傳回(因此您有機會在將它們傳回之前從原始項目創建和/或轉換值)。在後一種情況下,您需要創建一個類似於以下內容的類:
private class volatility { public double impliedVol; public double maturity; public double strike; }
然後,在您的方法中創建一個通用列表
getStrippedCapletVolatilitiesFromCapVolatilityCurve
,將一個新項目添加到該集合以使每一行返回,然後返回該列表/集合。FillRowMethod
將使用object
類型為 的第一個參數(as)呼叫您volatility
。這就是您out
將從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); }
double[][]
現在,可能可以將其作為從 main 返回的二維數組(即 )來處理SqlFunction
,但是隨後該FillRow
方法將被發送 adouble[]
,因為第一個維度被分解為對該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]); }
還:
我突然想到,您甚至可以放棄通用列表/集合併將
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; }
使用時有一些限制
yield return
,但是如果您的程序允許這種構造,那麼這不僅會更快,而且佔用的記憶體也更少。這些好處是由於此程式碼跳過了將getCapletCurveForGivenStrike()
方法的結果復製到單獨的集合(即通用列表)的步驟,只是為了將其返回到 T-SQL(在這種情況下,您需要等待它複製集合併使用更多記憶體)。在相關說明中:使用
Sql*
輸入參數的類型而不是標準的 .NET 類型。意思是,使用SqlString
代替string
和SqlDouble
代替double
。Value
然後,您可以通過所有類型都具有的屬性輕鬆地從那些中獲取 .NET 本機類型Sql*
(例如,SqlString.Value
傳回 astring
等)。有關一般使用 SQLCLR 的更多資訊,請訪問:SQLCLR 資訊