2012-09-26 22 views
7

有沒有辦法爲SQL Server創建CLR用戶定義函數,該函數返回多個值而不使用表值函數語法?例如,假設我想執行座標轉換,例如:帶有輸出參數的SQL Server CLR UDF - 可能嗎?

[SqlFunction()] 
public void ConvertCoordinates(SqlDouble x, SqlDouble y, SqlDouble z, out SqlDouble r, out SqlDouble t, out SqlDouble p) 
{ 
    r = new SqlDouble(Math.Sqrt((x.Value*x.Value)+(y.Value*y.Value)+(z.Value*z.Value))); 
    t = new SqlDouble(Math.Acos(r.Value/z.Value)); 
    p = new SqlDouble(Math.Atan(y.Value/x.Value)); 
} 

這甚至可能嗎?在這種情況下,表值函數看起來不合適,因爲計算永遠不會產生多於一個輸出行。使用標量值函數語法,我將不得不編寫三個不同的函數來執行計算並分別調用每個函數。鑑於我的實際使用情況,這是非常不切實際的。

我意識到上述邏輯可以使用純粹的T-SQL來完成;我的實際用例更復雜,但仍然只會導致單行有多個相互依賴的輸出值。

那麼,底線是可行的嗎?我不認爲這是事實,但人們可以希望。如果偶然的話它是可行的,那麼T-SQL看起來像是什麼調用這樣一個函數?

+1

UDF(無論是標量,表格,T-SQL還是CLR)都不能有參數。如果可以的話,如果你想要使用這些輸出,你必須發明新的語法來允許在'SELECT'子句中調用它。我不明白爲什麼一個返回單行的表值函數對你來說看起來很奇怪。 –

+1

@Damien這只是一個問題,是否可能。我自己的閱讀和實驗表明它可能不是(正如我所說的),但由於我是CLR整合的新手,我想問一下。當超過1行是可能的時,TVF對我來說似乎並不「奇怪」。 ALWAYS示例返回一行,但相關的返回值僅作爲一個集合有意義。在我的實際使用案例中,我正在爲數百萬行執行類似但較大的計算,所以如果出於參數的可能性,TVF似乎效率低下。簡單的「否」就足夠了。 – bporter

+0

@bporter - 顯然TVF將是最好的選擇 - 你自己說,他們「似乎不奇怪,當超過1行是可能的」,然後說你有數百萬行。 Ergo a(S)TVF就是答案!它將比遍歷每一行更有效率,比如強制性的foreach語句。 – gbjbaanb

回答

3

既然你已經採取了CLR暴跌,你可以創建自己的CLR類型使用它你可以做各種瘋狂的東西。作爲一個實際的例子,本地空間類型以這種方式實現,就像HierarchyID一樣。一旦你定義了你自己的類型,你可以讓你的函數返回它。如果獲得單個組件(如果我可以在你的案例半徑,theta和phi中假設),請在返回類型的方法上創建方法。

+0

感謝您的建議。 UDT會使這個更簡單,我也研究過它們。我唯一擔心的是我必須在每個數據庫中註冊程序集。就我而言,我是從過去10年左右積累的數百個數據庫中挖掘數據。 UDF看起來更簡單,因爲我可以將它們放在一個數據庫中,並從其他數據庫調用它們來執行計算。是否有一種方法可以使UDT在類似於空間類型的所有數據庫中都可用(無需在每個數據庫中註冊程序集)? – bporter

+0

我能想到幾種方法。首先是如果你只在一個數據庫中註冊一次,並在該數據庫的上下文中進行所有數據收集。另一種是將它部署到任何地方。由於它是T-SQL,你可能已經有辦法針對每個數據庫運行代碼,所以這不應該成爲問題。請記住,您可以通過腳本在腳本中直接部署程序集,而無需在任何地方部署DLL並引用它。 –

-1

我承認我還沒有嘗試過,但我想在T-SQL想,

DECLARE @X FLOAT(53), 
     @Y FLOAT(53), 
     @Z FLOAT(53), 
     @R FLOAT(53), 
     @T FLOAT(53), 
     @P FLOAT(53) 

EXEC ConvertCoordinates 
     @X = 0, 
     @Y = 0, 
     @Z = 0, 
     @R = @R OUTPUT, 
     @T = @T OUTPUT 
     @P = @P OUTPUT 
1

這是一個較老的問題,我在尋找一個非常類似問題的答案時找到了它。

SQL函數允許返回值,但不允許使用輸出參數。

SQL程序都允許輸出參數(但不返回值)

我發現這個從MSDN這裏的例子:

http://technet.microsoft.com/en-us/library/ms131092.aspx

[Microsoft.SqlServer.Server.SqlProcedure] 
public static void PriceSum(out SqlInt32 value) 
{ … } 

CREATE PROCEDURE PriceSum (@sum int OUTPUT) 
AS EXTERNAL NAME TestStoredProc.StoredProcedures.PriceSum 

當我嘗試將功能註冊到程序時一切都已經解決了。應該指出的是,一個函數可以有一個返回值,但是一個存儲過程不能。在我的情況下,我正在返回一個字符串值,併爲一些可選的詳細信息(如狀態代碼等)輸出參數。我所做的只是將我的方法更改爲void,並將字符串值作爲輸出參數傳回。

您的方法無論如何都是無效的,並且沒有返回值,因此是使用存儲過程而不是函數的完美候選。