您的位置:首页 > 数据库

SQL如何构建多条件组合查询,而且不降低效率

2007-12-12 14:10 639 查看
我们知道,在一般的信息系统中,特别是主要信息表,如客户基本信息,工单受理主界面,用户会用到多条件组合查询。

QQ群请加: 6539042(powerbuilder11&SQL)  

我看过一些系统,有的人是采用将一个表的栏位给用户选择,然后用户可以针对某一栏位来下条件,但是这违背多条件组合查询的需求初衷。多条件组合的需求是:用户在不同的视觉情况下,可以使用某个条件或者忽略某个条件,而且前面讲到的基于单表的按字段查询也不适用于复杂的数据结构,比如设计的系统结合的表很多,则将用户限制在单表的多字段是不行的。

我的做法是,作一个通用查询条件窗口出来作为模板,其它界面使用时通过另存或者继承,再修改为符合某个特定界面的条件查询窗。而某些条件如果某窗口用不到,可以让它enabled = false来解决。

我的查询条件公用窗是类似这样的。来自我的[ABCD客服自受理系统]:PB11



构建这个公用窗口的目的在于一劳永逸。但是要注意系统条件,常用的需要全部考虑在上面。

小提示:1. 对于不用的条件,enabled=false这样可以让用户不能填写,不发生杂乱难用的感觉。
                2. 对于常用的下拉列表框内容条目,比如上面的工单类型和业务类型,显然不要用"游标"从数据库里去fetch然后添加,因为这样会造成一些挂起,严重时锁表。(我最近看了一套自来水水管理系统,破解后看了看程序的event里很多程序代码,而且内嵌SQL很多。对于dropdownlist这样的填充用的是游标fetch。我分析就是个新手写的程序。客户反映说经常锁表。)其实这个例子应该是用一些办法在程序启动时,将一些FK表检索到本地的全局缓冲里,用的时候直接用,不需要每次都检索。对数据库应用来说,我遵循一个原则:尽量少地读数据库,充分考虑简单高效,并杜绝重复动作。如果你使用pb那就可以将一些表整个检索到datastore里,然后对填充dropdownlist这样的重复劳动,必然要写好全局函数来处理,不需要傻傻地作重复编码工作,或者将下拉框封装成自定义控件,传入dastore,用内部函数完成填充。

 注: 如果多选钮勾上,表明这个条件参加SQL查询,否则不参加,那怎么作到呢?技巧就是在SQL的条件里构建用and连接的多组条件,通过逻辑表达式的一个控制参数,如果某个多选框没选择,则直接忽略它。

我的SQL语句是这样的:

 SELECT serv_100001.docno,  serv_100001.docdate,  serv_100001.createuser, serv_100001.status   
  FROM serv_100001
    WHERE  (0 in (:control5) or
   (1 in (:control5) and serv_100001.status in(20)) or      --新录入
   (2 in (:control5) and serv_100001.status in(40,60)) or     --派单
   (3 in (:control5) and serv_100001.status in(80)) or      --签收
   (4 in (:control5) and serv_100001.status in(90,100,110)) or   --继续跟进
   (5 in (:control5) and serv_100001.status in(70)) or      --处理OK
   (6 in (:control5) and serv_100001.status in(120,130,140)))  and --回复客户结案
   (0 = :control6  or
   (0 = :control6 and  serv_100001.callnbr = ''))  and
   (0 = :control7 or
   (0 = :control7 and serv_100001.duty = 0)) 
   

这是我自己琢磨很久而想到的办法。并且在两套软件中使用。效果还可以。

执行的最后SQL带入条件参数后就是这样的:

SELECT serv_100001.docno, serv_100001.docdate, serv_100001.createuser, serv_100001.status   
FROM serv_100001
    WHERE (0 in (1,1,1,1,1,1) or
   (1 in (1,1,1,1,1,1) and serv_100001.status in(20)) or      
   (2 in (1,1,1,1,1,1) and serv_100001.status in(40,60)) or     
   (3 in (1,1,1,1,1,1) and serv_100001.status in(80)) or      
   (4 in (1,1,1,1,1,1) and serv_100001.status in(90,100,110)) or   
   (5 in (1,1,1,1,1,1) and serv_100001.status in(70)) or      
   (6 in (1,1,1,1,1,1) and serv_100001.status in(120,130,140))) and  
   (0 = 0  or
   (0 = 1 and  serv_100001.callnbr = ''))  and
   (0 = 0 or
   (0 = 1 and serv_100001.duty = 0)) 

//20071221修改更清晰一些。

我们很容易看明白。就是其中的controlx起到了很大作用,从而使得构建复杂的成组的条件容易实现,而且不影响到执行效率,因为逻辑关系式遵循短路原则。如果某组条件用户没勾选使用则control1=0就满足,从而不会执行后面的语句,整个分组条件就满足了,所以语句本身不影响速度。

*另外在网上有文章[使用Instr()与decode()进行多条件组合查询]介绍oracle下的函数,其实mssql用substring可以传入一个字符串作为参数,从而解决上面我的代码中的controlx太多的缺点。就是类似于control_string=“YYYYNNYY”,则substring(control_string,1,1)='Y'代表某个条件进行了勾选。当然还有charindex()函数可以用来传条件,比如多个条件传入的参数是:control_string=“A_CD_FGH”则代表A,C,D,F,G,H组的条件被勾选。用charindex('A',control_string)>0则可以判断A组条件被选择了。

*当然,如果你在pb中的话,数据框检索条件里是可以用control[10]这样的数组传入的,则SQL的where条件可以这样写: (1 in (:control_array) and id = :id)。每组条件用不同的编号。比如control_arrar={1,0,0,0,5,9},id=5传入后就是: (1 in (1,0,0,0,5,9) and id = 5),而且用这种方式传递比字符串传入速度更快。

*以上所说方法有一个前提就是控制参数必须在前面。利用逻辑运算的短路原则。用反了可就问题大了。

*另外asp的人说用sql_string="......." + "........."来拼凑代码,也是一个方法。但传递到服务器端的代码跟踪出来,可读性就非常差了。而且把检索看作一个接口的话,这个接口是不固定的,造成代码和数据逻辑的混杂不清。

如果大家有更好的办法,欢迎赐教。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息