2012-03-24 102 views
6

我需要編寫一個TSQL用戶定義的函數,它將接受一個字符串並返回一個數字。字符串表達式將被評估爲數字

我會打電話像dbo.EvaluateExpression('10*4.5*0.5')函數應該返回人數22.5

任何一個可以幫我寫這個功能EvaluateExpression

目前我正在使用CLR功能,我需要避免。

EDIT1

我知道這可以使用存儲過程來完成,但我想調用這個函數在一些語句例如:select 10* dbo.EvaluateExpression('10*4.5*0.5')

我也有大約40萬的公式是這樣進行評估。

EDIT2

我知道我們可以使用OSQL.EXE內部功能做得一樣解釋here。但由於權限設置,我也不能使用這個。

+0

的可能重複的[存儲在數據庫式(方程式)將在後面進行評估(SQL Server 2005中)](http://stackoverflow.com/questions/9722782/storing-formula-方程式在數據庫中要評估後來sql-server-2005) – Pondlife 2012-03-26 11:25:51

+0

你說你有一個工作的CLR功能,但「需要避免」它。如果你能解釋原因,這將有所幫助; TSQL不是一個很好的語言,你可能會遇到更多的問題,而不僅僅是使用CLR。 – Pondlife 2012-03-26 11:26:57

+0

我試圖避免CLR獲得性能和安全原因 – PraveenVenu 2012-03-27 04:26:55

回答

6

我不認爲這是可能的用戶定義函數。

你能做到這一點在存儲過程中,比如:

declare @calc varchar(max) 
set @calc = '10*4.5*0.5' 

declare @sql nvarchar(max) 
declare @result float 
set @sql = N'set @result = ' + @calc 
exec sp_executesql @sql, N'@result float output', @result out 
select @result 

但動態SQL,像execsp_executesql,在用戶定義的函數是不允許的。

+0

Yah。我已經嘗試過了,但是我想在一些語句中調用這個函數,例如:select * 10 * dbo.EvaluateExpression('10 * 4.5 * 0.5')' – PraveenVenu 2012-03-24 10:24:12

+1

AFAIK,這是無法在沒有CLR支持的情況下完成的,函數的限制是[相當廣泛](http://msdn.microsoft.com/en-us/library/ms191320.aspx) – Andomar 2012-03-24 10:34:20

+0

@PraVn:你可能想詳細說明你想做什麼,特別是在這些表達式來自。也許你可以將表達式和一些鍵一起存儲到臨時表中,讓存儲過程評估表達式,然後在查詢/查詢中使用臨時表(使用上述鍵加入),讀取/使用結果。 – 2012-03-24 21:57:33

0

使用此功能,它絕對可行。

CREATE FUNCTION dbo.EvaluateExpression(@list nvarchar(MAX)) 

RETURNS Decimal(10,2) 
AS 

BEGIN 
Declare @Result Decimal(10,2) 
set @Result=1 
DECLARE @pos  int, 
     @nextpos int, 
     @valuelen int 

SELECT @pos = 0, @nextpos = 1 


WHILE @nextpos > 0 
    BEGIN 
    SELECT @nextpos = charindex('*', @list, @pos + 1) 
    SELECT @valuelen = CASE WHEN @nextpos > 0 
          THEN @nextpos 
          ELSE len(@list) + 1 
         END - @pos - 1 

         Set @[email protected]*convert(decimal(10,2),substring(@list, @pos + 1, @valuelen)) 


    SELECT @pos = @nextpos 
    END 

RETURN @Result 
END 

您可以使用此

Select 10* dbo.EvaluateExpression('10*4.5*0.5') 
+0

它將適用於給定示例。但它不會評估所有表達式。對於例如:'10 +20'將失敗 – PraveenVenu 2012-03-24 14:31:18

+1

以這種方式來確認運算符優先級或括號很難,f.e. '10 + 20 *(5 + 1)' – Andomar 2012-03-24 22:21:11

+0

Andomar,你的代碼對此是正確的。謝謝 – 2012-07-13 09:12:53

0

我想你應該寫自己的FUNC使用遞歸。也許這將是有益使用逆波蘭式

3

免責聲明:我的項目Eval SQL.NET

對於SQL 2012+,你可以使用eval SQL.NET可與保護許可運行的所有者。

性能很好(比UDF好)並且尊重運算符的優先級和括號。事實上,幾乎所有的C#語言都受支持。

您還可以指定公式的參數。

-- SELECT 225.00 
SELECT 10 * CAST(SQLNET::New('10*4.5*0.5').Eval() AS DECIMAL(18, 2)) 

-- SELECT 70 
DECLARE @formula VARCHAR(50) = 'a+b*c' 
SELECT 10 * SQLNET::New(@formula) 
        .Val('a', 1) 
        .Val('b', 2) 
        .Val('c', 3) 
        .EvalInt() 
0

可以使用SQL存儲過程以下任意數量的變量計算任何公式的結果:

我在2012年寫的,可以評估任何類型的使用SQL Server數學公式的解決方案。該解決方案可以處理任何具有N個變量的公式:

我被要求找到一種方法來評估由用戶填充的公式給出的值。 公式包含數學運算(加法,乘法,除法和減法) 用於計算公式的參數存儲在SQL服務器DATA BASE中。

我發現我自己的解決方案是如下:

假設我有n個用於計算式的參數,這些參數的每被存儲在一個行中的一個數據表。 - 包含要在公式中使用的n行的數據表稱爲tab_value - 我必須在一個新表中使用SQL遊標 - 將n行(在tab_values中)中找到的n個值存儲在一行中我創建一個名爲tab_formula的新表格 - 在遊標中,我將爲每個值添加一個新列,列名稱將爲Id1,Id2,Id3等。 - 然後我構造一個SQL腳本,其中包含公式以評估公式

這裏完整的腳本後,我希望你覺得它有用,歡迎你問我。

該過程使用作爲輸入:含有用於計算公式

如果存在的值 -The式 -A表(從系統對象選擇1其中name = 'usp_evaluate_formula' 和的xtype =」 p')drop proc usp_evaluate_formula go

create type type_tab as table(id int identity(1,1),val decimal(10,2)) go create proc usp_evaluate_formula(@formula as nvarchar(100),@ values as type_tab readonly)as 開始 --KAMEL GAZZAH [email protected] --05/09/2016

聲明@tab_values表(ID INT,VAL十進制(10,2))

從@tab_values刪除插入@tab_values(ID,VAL) SELECT * FROM @values

聲明@id爲INT聲明@val爲十進制(10,2)

如果不存在(選擇1從系統對象,其中name =」 tab_formula') create table tab_formula(id int identity(1,1),式爲nvarchar(1000)) 如果不存在(來自tab_formula選擇1其中式= @式)插入到 tab_formula(式)的值(@formula)

c聲明光標選擇ID,從VAL聲明@tab_values @腳本爲 nvarchar(4000)打開c將文件提取到@id,@val而@@ fetch_status = 0 開始設置@script ='如果不存在(從syscolumns中選擇1內部 在c.id = o上加入sysobjects o .id其中o.name =''tab_formula''和 c。name =''id'+ convert(nvarchar(3),@ id)+''')alter table tab_formula add id'+ convert(nvarchar(3),@ id)+'decimal(10,2)'print @script exec(@script)set @ script ='update tab_formula set id'+ convert(nvarchar(3),@ id)+'='+ convert(nvarchar(10),@ val)+'其中 公式='''+ @ formula +''''print @script exec(@script)將c取回爲 @ id,@ val end close c deallocate c

set @ script ='select *,convert(decimal(10 ,2), '+ @式+') 「結果」 從tab_formula其中式= '' '+ @式+' ''」打印@Script EXEC(@Script)

聲明@mytab作爲type_tab插入@mytab(VAL)的值(1.56)插入到 @mytab(VAL)的值(15)插入到@mytab(VAL)的值(25)插入到 @mytab(VAL)的值(32)插入到@mytab(VAL)的值(17)插入到 @mytab(VAL)的值(33)插入到@mytab(VAL)的值(37.9)

EXEC usp_evaluate_formula 'cos(id1)+ cos(id2)+ cos(id3)+ cos(id4)+ cos(id5)+ cos(id6)+ cos(id7)/ cos(Id6)',@ mytab

go drop proc usp_evaluate_formula降型type_tab降表 tab_formula

相關問題