工作需求:根據不同條件查詢數據,目前有下拉列表和單選按鈕兩種
如果只是查詢具體的條件,那很簡單,只需要在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查詢臨時表的,這些代碼是不能處理的)