参加工作也一年又零了,但一直以来对Sql有一种敬畏的心理,可能更多的应该是“畏”的心理,主要是基础没有打好,对sql的应用也知道的甚少。昨天偶然间发现一个对于统计数据来说比较好用sql语句,下边作一下笔记。这里说的是hql语句,无所谓了,他们之间虽然说有很多不同,但是聚合函数的用法应该都是大同小异的。
首先来看表结构,我就直接贴bean中的代码了:

public class Assign {
 
	private Long id;
	//关联派工的人员
	private SysUser assignUser;
	//标识流程是否已经跑完,1或者是null是没有跑完,2是已经跑完的
	private String wfStatus;
	//状态(有三种状态,分别用0,1,2来表示)
	private String status; 
}

“assignUser”是关联的用户,我想要实现的功能是一个用户在流程跑完之后三种状态下分别有多少条数据,也就是说一个用户在流程跑完的数据中status为0的有多少条,status为1的有多少条……,实现思想:首先我们肯定要以用户分组来查,也就是说group by的字段应该是用户,分组之后我们要把status为0,1,2的数据的count值算出来,按照逻辑来写我们会写成count(status=0),count(status=1),count(status=2),所以按照我们的思路最后形成的hql语句为:

SELECT new list(a.assignUser.userName,count(a.STATUS=0),count(a.STATUS=1),
count(a.STATUS=2)) FROM Assign a WHERE a.wfStatus = 2 GROUP BY a.assignUser.userName

这样写出来的结果在mysql中测试通过,但是在oracle中却一直抛出“expecting CLOSE, found ‘=’”异常,最后改造成为:

SELECT new list(a.assignUser.userName,
sum(CASE WHEN a.STATUS = 0 THEN 1 ELSE 0 END),
sum(CASE WHEN a.STATUS = 1 THEN 1 ELSE 0 END),
sum(CASE WHEN a.STATUS = 2 THEN 1 ELSE 0 END) 
FROM Assign a WHERE a.wfStatus = 2 GROUP BY a.assignUser.userName

最后的结果经测试在mysql和oracle中都可以正常运行,采用最后这种写法有下面几个好处,
1,在高级语言中,CASE的可以用IF来替代,但是在SQL中不行;
2,CASE可以用于SQL语句和SQL存储过程、触发器,IF只能用于存储过程和触发器。因为CASE是SQL标准定义的,在SQL过程和触发器中,用IF替代CASE代价都相当的高,相当的麻烦,难以实现;
3,就是数据库兼容性好;
4,再一个就是这种写法是使用了sum函数来实现count函数的功效,但是除了实现count函数的功效,它还可以实现别的功能,看最后的hql代码中“THEN”后面我写了1,这里的“1”可以是数值也可以是字段名称,说到这里应该可以明白我的意思了。
最后说一下hql这种写法取值的方法:

StringBuffer hql = new StringBuffer("select new list("+
"a.assignUser.userName"+
"sum(CASE WHEN a.status = 0 THEN 1 ELSE 0 END),"+
"sum(CASE WHEN a.status = 1 THEN 1 ELSE 0 END),"+
"sum(CASE WHEN a.status = 2 THEN 1 ELSE 0 END) "+
"from Assign a where a.wfStatus = 2 group by a.assignUser.userName");
 
Query query = this.getSession().createQuery(hql.toString());
 
List<List> list =  query.list();
if (list != null && list.size() > 0) {
	for (List temp : list) {
		String userName = (String)temp.get(0);
		Integer status0 = (Integer)temp.get(1);
		Integer status1 = (Integer)temp.get(2);
		Integer status2 = (Integer)temp.get(3);
	}
}
/********************END****************************/