网站首页 > 技术文章 正文
经常写SQL存储过程的朋友,可能碰碰到这样的场景。比如我们要开发一份报表,利用存储过程返回记录集,但客户端传递过来的过滤条件就很难确定。最常见的过滤条件可能包括日期范围等,但还可能有各种不确定的过滤条件,这对我们写存储过程造成了很大的了压力。
有的朋友可能会把每个条件做为存储过程的一个传入参数,说实话这种方式会要人命的。特别是有的朋友开发的系统中、过滤条件窗口是自动生成的,调整下配置文件,就可以随时调整过滤窗口的过滤项目,过滤项目变了,存储过程的调用接口就变了,那不是每次都要重新编译程序啊?所以这种方式绝对是下下策了。
什么是过滤条件?
有朋友可能会问,什么叫做过滤条件?我本人是开发和实施ERP的,我就从我的系统中抓两张图给大家看一下:
上面两图中,红框框起来的可以称为过滤条件。过滤条件使用的目的,是把过滤的要求交给用户来设定,不同的过滤条件,过滤出不同的数据。
回到正题,如何解决这类问题呢?
笔者常用的方法是:将各种过滤项目和值一起打包成字符串,整体作为存储过程的一个传入参数,在存储过程中通过解析,将过滤项目和值分别再还原回来。
问题的核心在于如何解析,我常用的有两种方法,一种方法是采用:
过滤项目1=值1, 过滤项目2=值2 ...
这种方式的特点是将键值用逗号隔开,无论客户端的过滤条件有多复杂,我们只需要修改我们的存储过程就行了,而不需要动不动就要去重新编译客户端程序。
另一种方法是打包成Json传入。Json解析方式比较复杂些,但最好用,留下一次再说。这次主要说说第一种方式如何解析。
演示数据准备
为了演示方便,我们先准备一些初始数据,就用我常用的销售表:
declare @sale table( FDate smalldatetime, FName nvarchar(50), FDistrict nvarchar(50), FAmount decimal(28,10) ); insert into @sale values ('2018-12-27','张三','北京',20000), ('2018-12-27','张三','上海',50000), ('2018-12-27','张三','深圳',40000), ('2018-12-27','张三','广州',30000), ('2018-12-27','李四','北京',30000), ('2018-12-27','李四','上海',50000), ('2018-12-27','李四','深圳',40000), ('2018-12-27','李四','广州',10000);
数据参考下图:
存储过程的传入参数值如下:
FBegDate=2018-12-01,FEndDate=2018-12-31,FName=张三,FDistrict=深圳
对打包过滤条件的解析过程
解析的过程主要用到SQLServer的substring函数,通过while循环进行解析,代码比较长,我把核心的解析过程放进来,如果您刚好对这个有兴趣,拿去稍微改造下就成您的了。先要告诉您的是,变量@memos其实就是上述的存储过程的传入参数,@begdate、@enddate、@name、@district要存放从上述参数中解析出来的开始日期、结束日期、姓名和区域。如果必要参数没有值,为了演示方便我这里直接使用了Print,其实在真正应用时您可以将错误返回。这个脚本稍微改造下,对MySQL、PostgreSQL、FirebirdSQL、Oracle都是通用的。
--解析使用的变量 declare @pos bigint, @beg bigint, @end bigint, @str nvarchar(1000), @char nvarchar(1), @memos nvarchar(2000), @key nvarchar(30), @field nvarchar(50), @val nvarchar(50); --获取的数据 declare @begdate smalldatetime, @enddate smalldatetime, @name nvarchar(100)=space(0), @district nvarchar(100)=space(0); --初始化传入变量 set @memos='FBegDate=2018-12-01,FEndDate=2018-12-31,FName=张三,FDistrict=深圳'; --解析过程 set @pos=1; set @beg=1; set @key=space(0); set @memos=@memos+','; set @end=len(@memos); set @field=space(0); set @val=space(0); set @str=space(0); while @pos<=@end begin --将所有的部分循环完全 set @char=substring(@memos,@pos,1); if @char=',' begin set @val=@str; set @str=space(0); if @field='FBegDate' begin if ISDATE(@val)=1 begin set @begdate=convert(datetime,@val); end else begin print '需要设置开始日期!'; end end else if @field='FEndDate' begin if ISDATE(@val)=1 begin set @enddate=convert(datetime,@val); end else begin print '需要设置结束日期!'; end end else if @field='FName' begin set @name=@val; end else if @field='FDistrict' begin set @district=@val; end end else if @char='=' begin set @field=@str; set @val=space(0); set @str=space(0); end else begin set @str=@str+@char; end set @pos=@pos+1; end
解析之后的过滤项目值的使用
等到您需要的过滤项目值解析出来了,您就可以在SQL查询中使用了:
select FDate as F日期, FName as F姓名, FDistrict as F区域, FAmount as F销售额 from @sale where FDate>=@begdate and FDate<=@enddate and FName=(case when len(@name)>0 then @name else FName end) and FDistrict=(case when len(@district)>0 then @district else FDistrict end);
上述的脚本里面,大家可能会对case语句有些不解,其目的是判断是否传来了可用的姓名或区域,如果没有就不参与过滤的意思。
在头条中放太多代码看起来太费劲,我把完整的代码截图下来,供有兴趣的朋友参考:
需要完整脚本的朋友,可以在下面留下邮箱,我会发给您。
希望对您有所帮助!
猜你喜欢
- 2024-09-14 Mysql:替换某个字段中的部分字符串——replace函数
- 2024-09-14 plsql字符串分割浅谈(plsql字符串截取)
- 2024-09-14 oracle函数--INSTR、SUBSTR使用说明和实例讲解
- 2024-09-14 详解Oracle使用substr和instr截取字符串指定位置的字符
- 2024-09-14 mysql 替换某一个字段中的字符串(mysql替换一个字符串的字符函数为)
- 2024-09-14 sql注入总结(sql注入示例)
- 2024-09-14 Mybatis 中的 DAO 接口和 XML 文件里的 SQL他们如何建立关系?
- 2024-09-14 SQL Server - 字符串常用操作(sqlserver 字符类型)
- 2024-09-14 如何在Java中比较字符串?(如何在java中比较字符串个数)
- 2024-09-14 SQL截取函数(substr)与字符串查找函数(Instr)的组合应用
- 1512℃桌面软件开发新体验!用 Blazor Hybrid 打造简洁高效的视频处理工具
- 556℃Dify工具使用全场景:dify-sandbox沙盒的原理(源码篇·第2期)
- 504℃MySQL service启动脚本浅析(r12笔记第59天)
- 482℃服务器异常重启,导致mysql启动失败,问题解决过程记录
- 480℃启用MySQL查询缓存(mysql8.0查询缓存)
- 460℃「赵强老师」MySQL的闪回(赵强iso是哪个大学毕业的)
- 440℃mysql服务怎么启动和关闭?(mysql服务怎么启动和关闭)
- 438℃MySQL server PID file could not be found!失败
- 最近发表
- 标签列表
-
- c++中::是什么意思 (83)
- 标签用于 (65)
- 主键只能有一个吗 (66)
- c#console.writeline不显示 (75)
- pythoncase语句 (81)
- es6includes (73)
- windowsscripthost (67)
- apt-getinstall-y (86)
- node_modules怎么生成 (76)
- chromepost (65)
- c++int转char (75)
- static函数和普通函数 (76)
- el-date-picker开始日期早于结束日期 (70)
- js判断是否是json字符串 (67)
- checkout-b (67)
- c语言min函数头文件 (68)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- & (66)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- eacces (67)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)