Hql实战:有关包含子查询的Hql语句生成查询总记录数Hql的解决办
前几天,工作中无意发现系统中的通用分页查询方法里的获取总记录数hql方法不支持子查询,因为方法首先去除group by,order by,然后 获取from的索引index,然后sunString(index),最后拼接上select count(*),这样显然不对,如果有子查询,生成的hql就是错误的。于是我就一直在考虑要写个通用方法还获取查询总记录数的hql,不用再考虑hql是否包含子查询。由于子查询理论上是可以无限级嵌套的,所以问题就变得很棘手。

刚开始,我把子查询大概有几种形式列了出来,试图找出其中的规律,可能看了几天,依然无果,后来在以前北大青鸟的校友群里得到以前的班长的提示,发现了规律:主查询的from关键字不在括号()之间,于是问题就集中在如何获取不在括号()之间的from关键字的索引,也就是说,刚开始我的思考方向是,如何找出不是子查询的from的索引,但是怎么查找了,这时很自然想到正则表达式。可是子查询可能有很多级嵌套的,于是就涉及到正则表达式的递归匹配,对于PHP等其他语言来说,他们支持正则递归匹配,杯具的是,JDK暂不支持正则表达式递归匹配语法,所以我又再度思路受堵陷入沉思。其间,我有问群里的朋友,可惜木有谁能让我茅塞顿开。于是,我不停的google,遗憾的是没找到一篇相关有意义的文章,都是千篇一律互相转载,毫无原创性,再次失望。没办法,只好自己思考。也不知道是啥原因,今天晚上回来,突然来灵感了,有了点小突破,我转换了思路:如果我能用正则匹配到所有子查询,然后把子查询都替换成空字符串,那不就可以,当然where部分的子查询不能替换,因为他会影响总记录数,为了刚开始不把问题搞得太复杂化,所以我暂时没考虑where子查询的过滤问题。子查询有什么规律,这个很容易想到,就是在括号()之间,于是我翻着正则表达式手册,不停的尝试着写demo,这是我写的第一个demo,
Strings= "<div><div><font></font></div><div><span><ul><li><a></a></li><li><a></a></li><li><a></a></li></ul></span></div></div><div>1</div><div>2</div>";
String regex = "<\\w*[^>^/]*>([^<^>]*?)</\\w*>";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
while(m.find()){
System.out.println(m.group());
}
让我感觉有点眉目了这个正则是匹配不包含子标签的标签,即叶子标签,
我们的子查询跟这个很相似,也是一层一层的嵌套,如果能一层一层的往外替换,那子查询就可以移除了。于是我对上面的正则进行了修改,
String s = "select a.id,(select * from E e where e.id in(select f.id from F f)),(select c.name from C c where c.id = a.cid) from A a where a.id in(select b.aid from B b)";
String regex = "\\([^)]*([^(^)]*?)\\)";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
while(m.find()){
System.out.println(m.group());
}
可是上面的正则会把主查询的where部分子查询匹配出来了,where部分子查询如何过滤掉,成了问题的关键,于是再次改造, String regex = "[^in]\\([^)]*([^(^)]*?)\\)";
到此,问题基本解决,途中发现了一个BUG,in后面如果有空格,不能过滤,所以我又修改了下
String regex = "[^in\\s]+\\([^)]*([^(^)]*?)\\)";这样基本上就可以应付所有情况下的子查询了。但我不能保证100%没有BUG,至少暂时没发现。最后附上我测试写的所有草稿代码:
package com.lxw.oa.test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Lanxiaowei
* @createTime 2011-9-8 下午06:31:32
*/
public class Test2 {
public static void main(String[] args) {
/*String s = "<div><div><font></font></div><div><span><ul><li><a></a></li><li><a></a></li><li><a></a></li></ul></span></div></div><div>1</div><div>2</div>";
String regex = "<\\w*[^>^/]*>([^<^>]*?)</\\w*>";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
while(m.find()){
System.out.println(m.group());
}*/
/*String s = "select a.id,(select * from E e where e.id in(select f.id from F f)),(select c.name from C c where c.id = a.cid) from A a where a.id in(select b.aid from B b)";
String regex = "[^in]\\([^)]*([^(^)]*?)\\)";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(s);
while(m.find()){
System.out.println(m.group());
}*/
//String hql = "select * from Student s where s.name like %a% group by s.id order by s.id desc";
//System.out.println(removeGroupBy(hql));
String s = "select a.in,(select * from E e where e.id in(select f.id from F f)),(select c.name from C c where c.id = a.cid) from A a where a.id in (select b.aid from B b) group by a.id order by a.id desc";
String h = getTotalHql(removeByKey(s,"group by"));
System.out.println(h);
}
/**
* 移除key指定的子句,如order by,group by
*/
private static String removeByKey(String hql,String key){
int index = hql.indexOf(key.toLowerCase());
if(index == -1){
return hql;
}
return hql.replace(hql.substring(index),"");
}
/**
* 移除distinct关键字
*/
private static String removeDistinct(String hql){
if(hql.indexOf("distinct") == -1){
return hql;
}
return hql.replace("distinct","");
}
/**
* 移除select部分子查询
* @param hql 传入的hql语句
*/
private static String removeSubSelect(String hql){
String regex = "[^in\\s]+\\([^)]*([^(^)]*?)\\)";
Pattern p = Pattern.compile(regex);
Matcher m = p.matcher(hql);
while(m.find()){
String sub = m.group();
hql = hql.replace(sub, "");
}
return hql;
}
/**
* 获取总记录数Hql
*/
private static String getTotalHql(String hql){
String s = removeSubSelect(hql);
int from = s.indexOf("from");
return "select count(*) " + s.substring(from);
}
}
本文来源 我爱IT技术网 http://www.52ij.com/jishu/108.html 转载请保留链接。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
