zoukankan      html  css  js  c++  java
  • 去除SQL语句某查询条件

    工作需求:根据不同条件查询数据,目前有下拉列表和单选按钮两种

    如果只是查询具体的条件,那很简单,只需要在where 条件之后加上相应的条件即可,像这样:where type = ‘门诊’。当查询的是全选或全部时,显然的就要把相应的条件给去除,如果你是使用mybatis,那也很简单,只需要在xml映射文件里加上一些判断条件,像这样:

    <select id="user" parameterType="user" resultType="User">
            select * from user 
              <where>
                <if test="id!=null and id!=''">
                  id=#{id}
                </if>
                <if test="type!=null and type!=''">
                  and type=#{type}
                </if>
                <if test="gender!=null and gender!=''">
                  and gender=#{gender}
                </if>
              </where>
           </select>

    但是项目中的需求往往千奇百怪,由于我的SQL语句是写在json配置文件里的,而我又使用的是mybatis框架,我没办法将SQL语句直接写在mybatis的xml映射文件里,我只有把SQL作为一个参数传递给映射文件,就像上面传递id,type,gender一样。

    <select id="executeSQL" parameterType="java.lang.String" resultType="Map">
            <![CDATA[ ${SQL} ]]> 
        </select>

    因为我传递的是一句SQL语句而不是具体条件,当我的SQL语句里出现特殊字符如比较字符时XML是会帮我转义的,我不需要XML去转义我的SQL,所以我要使用

     <![CDATA[  ]]> 

    将我的SQL语句包裹起来,这样SQL语句就不会被转义了。这里使用${ SQL }而不是#{ SQL },#将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号,$将传入的数据直接显示生成在sql中,显然我的SQL语句不需要加双引号。(这里我也先不考虑使用$会导致SQL注入的问题,后期我也会去做SQL检查)

    现在背景已经明确,如果想完成需求,我只有在SQL进入XML映射文件之前,将一些条件处理掉。SQL是写在json配置文件里的,预先的条件也是写死的,如下:

    "sql":"SELECT nvl(sum(a.ssrc),0) as count FROM CB_ME_YLZL a,CB_DI_DATE b,CB_DI_YLJG c,CB_DI_JZLX d WHERE a.sjid=b.sjid and a.yljgid=c.yljgid and a.jzlxid=d.jzlxid and c.yljgdj='3' and c.yljgmc = #{select1_val_select}  AND type = #{radio1_val_radio}"

    当用户选择全选或是全部时,我需要把

    and c.yljgmc = #{select1_val_select}  AND type = #{radio1_val_radio}

    去掉。不是全选或全部时我需要把

    #{select1_val_select}   #{radio1_val_radio}

    替换成相应的条件。

    代码如下:

    /**
         * 处理SQL语句
         * 
         * @param sql
         * @return
         */
        public static String dealSQL(String sql, String str) {
            sql = sql.trim().toUpperCase().replaceAll(" +", " ");
            int form = sql.indexOf(" FROM ");
            String begin = sql.substring(0, form);
            begin = begin.replaceAll(" AS ", " AS C_");
            String end = sql.substring(form, sql.length());
            sql = begin+end;
            String[] split1 = str.trim().toUpperCase().replaceAll("'", "").replaceAll(""", "").split(",");
            for (String s : split1) {
                if(StringUtils.isNotBlank(s)) {
                    String[] split2 = s.split(":");
                    
                    if(sql.contains(split2[0])) {
                        if(split2[0].contains("VAL_RADIO") || split2[0].contains("VAL_SELECT")) {
                                if(split2[1].equals("全选") || split2[1].equals("全部")) {
                                    sql = removeSQL(sql,"#{"+split2[0]+"}");
                                }else {
                                    sql = sql.replace("#{"+split2[0]+"}", "'" + split2[1] + "'");
                                }
                        }else {
                            sql = sql.replace("#{"+split2[0]+"}", "'" + split2[1] + "'");
                        }
                    }
                }
            }
            return sql;
        }

    json配置文件里规定需要展现的字段都要使用as ** 作为别名,但是如果别名为数字或特殊字符的话,oracle是不认的,如果别名使用双引号引起来,orace认但json文件又不认了,所以我使用最low的办法,将所有别名加上一个C_,这样数据库就认了。

    看一下  removeSQL方法:

    /**
         * 去除SQL语句某查询条件
         * @param sql
         * @param choice
         * @return
         */
        public static String removeSQL(String sql,String choice) {
            int cho_first = sql.indexOf(choice);
            int before_and = sql.lastIndexOf(" AND ", cho_first);
            int before_where = sql.lastIndexOf(" WHERE ", cho_first);
            int after_and = sql.indexOf(" AND ", cho_first);
            int after_where = sql.indexOf(" WHERE ",cho_first);
            
            if(before_where != -1) {
                if(before_and != -1) {
                    if(before_and > before_where) {
                        sql = sql.replace(sql.substring(before_and, cho_first), " ").replace(choice, " ");
                    }else {
                        if(after_and != -1) {
                            if(after_where != -1) {
                                if(after_and < after_where) {
                                    sql = sql.replace(sql.substring(before_where+7, after_and+5), " ");
                                }else {
                                    sql = sql.replace(sql.substring(before_where, cho_first), " ").replace(choice, " ");
                                }
                            }else {
                                sql = sql.replace(sql.substring(before_where+7, after_and+5), " ");
                            }
                        }else {
                            sql = sql.replace(sql.substring(before_where, cho_first), " ").replace(choice, " ");
                        }
                    }
                }else{
                    if(after_and != -1) {
                        if(after_where != -1) {
                            if(after_and < after_where) {
                                sql = sql.replace(sql.substring(before_where+7, after_and+5), " ");
                            }else {
                                sql = sql.replace(sql.substring(before_where, cho_first), " ").replace(choice, " ");
                            }
                        }else {
                            sql = sql.replace(sql.substring(before_where+7, after_and+5), " ");
                        }
                    }else {
                        sql = sql.replace(sql.substring(before_where, cho_first), " ").replace(choice, " ");
                    }
                }
            }
            
            int cho = sql.indexOf(choice);
            if(cho != -1) {
                return removeSQL(sql,choice);
            }else {
                return sql;
            }
        }

    逻辑也就是:当条件在不同地方,处理方式不同而已,下面是几种罗列的可能存在条件的地方,上面代码就是针对这些不同地方,将这些条件连同其前的and或者where(不影响其后的and条件使用的where,如下图第二条语句第一处位置的条件)去掉。(针对复杂的SQL,如使用with as 将查询数据做临时表,之后再使用select查询临时表的,这些代码是不能处理的)

    前进时,请别遗忘了身后的脚印。
  • 相关阅读:
    P2788 数学1(math1)- 加减算式
    数据库第三章-学习笔记
    字典序
    P1739 表达式括号匹配
    P3742 umi的函数
    P1765 手机
    P2192 HXY玩卡片
    全排函数c++ next_permutation()
    11.css定义下拉菜单
    10.php引用(&)详解及注意事项
  • 原文地址:https://www.cnblogs.com/liudaihuablogs/p/9181949.html
Copyright © 2011-2022 走看看