一、整體思路:循環遍歷表達式字符串,設置一個index從第一個字符開始檢測當前數字是否可以和后面的數字進行運算,如果可以運算,將兩個數挑出來運算,然后用運算的結果替換原來表達式中的這兩個數和符號,計算后index又從1開始。如果不能運算則將當前index指向第二個數。如此循環直到表達式全部計算完畢。(簡單的用一句話概括就是,找到優先級最高且靠前的兩個子項先運算)
二、代碼:
整體拆分成四個方法
SimpleCalculate匹配加減乘除char去計算兩個數的結果

Create function [dbo].[SimpleCalculate](@num1 float,@num2 float,@sign char) returns float as begin declare @result float if @sign='+' begin set @result=@num1+@num2 end else if @sign='-' begin set @result=@num1-@num2 end else if @sign='*' begin set @result=@num1*@num2 end else if @sign='/' begin set @result=@num1/@num2 end return @result end GO
GetIsCal:比兩個符號的優先級,第一個符號優先級高於第二個返回1(在下面介紹的[GetNumCondition]函數中會用到)

CREATE FUNCTION [dbo].[GetIsCal](@sign1 char, @sign2 char) returns int as begin declare @isCal int if (@sign1='+' or @sign1='-') and (@sign2='+' or @sign2='-') begin set @isCal= 1 return @isCal end else begin set @isCal= 0 end if (@sign1='*' or @sign1='/') and @sign2<>'(' begin set @isCal= 1 return @isCal end else begin set @isCal= 0 return @isCal end return @isCal end GO
GetNumCondition:返回當前index指向的數字是否能進行運算,以及當前運算的數和運算符

CREATE FUNCTION [dbo].[GetNumCondition](@exp nvarchar(max), @index int) returns @tmp table(numOne float,numTwo float, endindex int ,thissign char,nextsign char,Iscalc int,aa nvarchar(30)) as begin insert @tmp(numOne) Values(null) declare @isEnd int declare @flag int declare @end int declare @thissign char declare @nextsign char set @end=0 set @end=@index+1 set @flag=1 --1表示 搜索第一個數字 2表示搜索第二個數字 set @isEnd=0 while @isEnd=0 begin if @flag=1 begin --搜索第一個數 if ISNUMERIC('1'+ SUBSTRING(@exp,@end,1))=1 begin --表示沒有搜索到特殊符號 set @end= @end+1 continue; end else begin --表示搜索到特殊符號,第一個數搜索完畢 set @flag=2 update @tmp set numOne=SUBSTRING(@exp,@index,@end-@index) update @tmp set thissign=SUBSTRING(@exp,@end,1) set @index= @end+1 set @end= @index+1 if SUBSTRING(@exp,@index,1)='(' begin --第一個數的運算符后面是括號,不可運算,直接返回index值 update @tmp set Iscalc=0 update @tmp set endindex=@index+1 break end end end set @thissign=(select top 1 thissign from @tmp) if @flag=2 begin --if @thissign ='(' begin --end if ISNUMERIC( '1'+SUBSTRING(@exp,@end,1))=1 and SUBSTRING(@exp,@end,1) is not null and SUBSTRING(@exp,@end,1)!='' begin -- set @end= @end+1 continue; end else begin --第二個數搜索完畢,開始更新返回值 if SUBSTRING(@exp,@end,1)=')' or SUBSTRING(@exp,@end,1)='' begin --兩個數前后是括號,可以直接運算 update @tmp set Iscalc=1 update @tmp set endindex=@end-1 update @tmp set numTwo=SUBSTRING(@exp,@index,@end-@index) break end set @isEnd=1 update @tmp set numTwo=SUBSTRING(@exp,@index,@end-@index) update @tmp set nextsign=SUBSTRING(@exp,@end,1) set @nextsign=SUBSTRING(@exp,@end,1) update @tmp set Iscalc=dbo.GetIsCal(@thissign,@nextsign) if dbo.GetIsCal(@thissign,@nextsign)=1 begin update @tmp set endindex=@end-1 end else begin update @tmp set endindex=@index end end end end return end GO
主函數[GetExpressionResult]計算表達式

ALTER function [dbo].[GetExpressionResult](@exp nvarchar(max)) returns nvarchar(max) as begin declare @index int set @index=1 while ISNUMERIC(@exp)=0 begin declare @isCal int declare @endindex int select @isCal=Iscalc ,@endindex=endindex from dbo.GetNumCondition(@exp,@index) if @isCal=1 begin declare @numOne float declare @numTwo float declare @sign char declare @cur_reslut float select @numOne=cast(numOne as float),@numTwo=cast(numTwo as float),@sign=thissign from dbo.GetNumCondition(@exp,@index) set @cur_reslut=dbo.SimpleCalculate(@numOne,@numTwo,@sign) if SUBSTRING(@exp,@index-1,1)='(' and SUBSTRING(@exp,@endindex+1,1)=')' begin set @exp=SUBSTRING(@exp,1,@index-2)+cast(@cur_reslut as nvarchar(20))+SUBSTRING(@exp,@endindex+2,len(@exp)-@endindex) end else begin set @exp=SUBSTRING(@exp,1,@index-1)+cast(@cur_reslut as nvarchar(20))+SUBSTRING(@exp,@endindex+1,len(@exp)-@endindex) end set @index=1 end else begin set @index=@endindex continue; end end return @exp end GO
總結:業務需求中需要用到此方法,如若有錯誤和更多思路請不吝賜教, 另外有一篇文章的方法更加簡潔:https://blog.csdn.net/scott_he/article/details/25835273