去除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查詢臨時表的,這些代碼是不能處理的)


免責聲明!

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



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