SQL計算算數表達式的函數自定義(加減乘除)


一、整體思路:循環遍歷表達式字符串,設置一個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
View Code

 

 

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
View Code

 

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
View Code

 

 

主函數[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
View Code

 

 

 

總結:業務需求中需要用到此方法,如若有錯誤和更多思路請不吝賜教,            另外有一篇文章的方法更加簡潔:https://blog.csdn.net/scott_he/article/details/25835273

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM