一、整体思路:循环遍历表达式字符串,设置一个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(''+ 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( ''+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

SQL计算算数表达式的函数自定义(加减乘除)的更多相关文章

  1. Oracle SQL Lesson (3) - 使用单行函数自定义输出

    大小写转换函数LOWER('SQL Course') = sql courseUPPER('SQL Course') = SQL COURSEINITCAP('SQL Course') = Sql C ...

  2. EL表达式 EL函数 自定义el函数 《黑马程序员_超全面的JavaWeb视频教程vedio》

    \JavaWeb视频教程_day12_自定义标签JSTL标签库,java web之设计模式\day12_avi\12.EL入门.avi; EL表达式 1. EL是JSP内置的表达式语言! * jsp2 ...

  3. SQL Fundamentals: Using Single-Row Functions to Customize Output使用单行函数自定义输出

    SQL Fundamentals || Oracle SQL语言 DUAL is a public table that you can use to view results from functi ...

  4. 在论坛中出现的比较难的sql问题:31(row_number函数+子查询 月环比计算)

    原文:在论坛中出现的比较难的sql问题:31(row_number函数+子查询 月环比计算) 所以,觉得有必要记录下来,这样以后再次碰到这类问题,也能从中获取解答的思路.

  5. Vue.js 第2章 钩子函数&自定义指令&过滤器&计算属性&侦听器

    目标 钩子函数 自定义指令 自定义过滤器 计算属性 监听属性 局部自定义指令 为什么需要自定义指令 为了复用,为了代码的灵活 指令的分类:全局指令,局部指令 在vm外面创建的指令 通过Vue.dire ...

  6. Java工作流引擎节点接收人设置“按自定义SQL计算”系列讲解

    关键字: 驰骋工作流程快速开发平台 工作流程管理系统 工作流引擎 asp.net工作流引擎 java工作流引擎. 开发者表单  拖拽式表单 工作流系统CCBPM节点访问规则接收人规则 适配数据库: o ...

  7. SQL Fundamentals || Single-Row Functions || 转换函数 Conversion function

    SQL Fundamentals || Oracle SQL语言   SQL Fundamentals: Using Single-Row Functions to Customize Output使 ...

  8. SQL几种常用的函数

    函数的种类: 算数函数(数值计算的函数) 字符串函数(字符串操作的函数) 日期函数(用来进行日期操作的函数) 转换函数(用来转换数据类型和值的函数) 聚合函数(用来进行数据聚合的函数) 算数函数(+- ...

  9. Sql总结之Sql--常用函数

    控制流函数 IFNULL(expr1,expr2) 如果expr1不是NULL,IFNULL()返回expr1,否则它返回expr2.IFNULL()返回一个数字或字符串值,取决于它被使用的上下文环境 ...

随机推荐

  1. vscode 保存自动 格式化eslint 代码

    在网上找了很多种方法,大多都没有成功  一下是一种成功的 配置方法: 1) First, you need to install the ESLint extension in the VS code ...

  2. 数据库学习 day1 认识数据库

    从SQL的角度而言,数据库是一个以某种有组织的方式储存的数据集合. 我们可以把它比作一个“文件柜”,这个“文件柜”是一个存放数据的物理位置,不管数据是什么,也不管数据是如何组织的. 下面介绍几个术语 ...

  3. MTK Android 平台语言支持状态

    Language English Name Chinese Name Code GB ICS  JB  KK L العربية Arabic(Israel) 阿拉伯语(以色列) ar_IL Y Y ...

  4. 解决:docker-compose端口绑定

    docker-compose 进程绑定 Bind for 0.0.0.0:3825 failed: port is already allocated 查看进程发现有进程在关闭后继续进行 docker ...

  5. 汇编刷题 已知整数变量A和B,试编写完成下列操作的程序

    1.若两个数中有一个是奇数,一个是偶数,则将它们互换储存地址 2.若两个数都是奇数,则分别加一 3.若两个数都是偶数,则不变 DATA SEGMENT A DB 12H B DB 25H DATA E ...

  6. beanshell自定义聚合报告时分线程组阶段展示

    假设现在一共会加载100个线程,期望聚合报告中分别展示1-20,20-40,40-60,60-80的四个阶段的线程并发性能数据,而不是总体的统计数据 beanshell脚本,具体内容: import ...

  7. 【Selenium07篇】python+selenium实现Web自动化:PO模型,PageObject模式!

    一.前言 最近问我自动化的人确实有点多,个人突发奇想:想从0开始讲解python+selenium实现Web自动化测试,请关注博客持续更新! 这是python+selenium实现Web自动化第七篇博 ...

  8. 搭建WEB、NFS共享、sersync实时同步以及全网定时备份服务流程

    本次实验的主要目的: 1.搭建web服务,使用nfs服务共享的/data目录挂载到web站点目录上. 2.nfs服务器与backup服务器使用sersync实时同步/data目录中的文件. 3.bac ...

  9. springboot项目war包部署及出现的问题Failed to bind properties under 'mybatis.configuration.mapped-statements[0].

    1.修改pom文件 修改打包方式 为war: 添加tomcat使用范围,provided的意思即在发布的时候有外部提供,内置的tomcat就不会打包进去 <groupId>com.scho ...

  10. yum 下载全量依赖 rpm 包及离线安装(终极解决方案)

    目录 简介 验证环境 查看依赖包 方案一(推荐):repotrack 方案二:yumdownloader 方案三:yum 的 downloadonly 插件 离线安装 rpm 参考资料 简介 通常生产 ...