问题描述:
由于在SELECT字句常带有聚合函数,这时如果是非聚合函数的表达式也出现在SELECT子句中,则此非聚合函数的表达式必须在GROUP BY中出现。如:查询 AI_94传票对照表.省/市代号, 求和(AI_94传票对照表.金额) 来自 AI_94传票对照表 条件 AI_94传票对照表.金额 大于 0 分组 AI_94传票对照表.省/市代号。
情况说明<目前整理出了常用的几种场景>:
①在SELECT中的非聚合函数的字段或表达式必须在GROUP BY中出现
SELECT CORP_MEMBER_CODE AS f1, SUBSTRING(META_SORT_CODE, 1, 4) AS f2, SUM(PRICE) AS f3
FROM MT_CORP_PRODUCT_PRICE
GROUP BY CORP_MEMBER_CODE, SUBSTRING(META_SORT_CODE, 1, 4)
②在SELECT中没有出现的字段或表达式可以在GROUP BY中出现
SELECT CORP_MEMBER_CODE AS f1, SUBSTRING(META_SORT_CODE, 1, 4) AS f2, SUM(PRICE) AS f3
FROM MT_CORP_PRODUCT_PRICE
GROUP BY CORP_MEMBER_CODE, SUBSTRING(META_SORT_CODE, 1, 4), PRODUCT_NAME
③在SELECT中的表达式如果为一个字段组成,则此字段如果在GROUP BY中出现,那么SELECT对应的表达式可以不在GROUP BY出现
SELECT CORP_MEMBER_CODE AS f1, SUBSTRING(META_SORT_CODE, 1, 4) AS f2, SUM(PRICE) AS f3
FROM MT_CORP_PRODUCT_PRICE
GROUP BY CORP_MEMBER_CODE, META_SORT_CODE
④在SELECT中的表达式如果为多个字段组成,则SELECT对应的表达式必须在在GROUP BY出现(建议设置表达式的字段个数标识)
SELECT CORP_MEMBER_CODE AS f1, SUBSTRING(META_SORT_CODE, 1, 4) AS f2,
(PRODUCT_NUMBER1 + PRODUCT_NUMBER2) as f3, SUM(PRICE) AS f4
FROM MT_CORP_PRODUCT_PRICE
GROUP BY CORP_MEMBER_CODE, SUBSTRING(META_SORT_CODE, 1, 4), (PRODUCT_NUMBER1 + PRODUCT_NUMBER2)
⑤在SELECT中的字段/表达式如果为一个常量,则一定不能GROUP BY中出现
SELECT CORP_MEMBER_CODE AS f1, SUBSTRING(META_SORT_CODE, 1, 4) AS f2,
PRODUCT_NUMBER1 + PRODUCT_NUMBER2 AS f3, SUM(PRICE) AS f4, 888 AS f5
FROM MT_CORP_PRODUCT_PRICE
GROUP BY CORP_MEMBER_CODE, META_SORT_CODE, PRODUCT_NUMBER1 + PRODUCT_NUMBER2
处理过程:
1、增加聚合函数模型对象AggregateFuncModel,继承普通函数模型对象FunctionModel
2、普通函数setFilter方法修改为protected
3、修改了语法树遍历函数的代码,如下:
1
2 function returns [FunctionModel model]
3 {
4 model=null;
5 ParametersModel p;
6 ExpressionModel express1 = new ExpressionModel();
7 }
8 : //Aggregate functions聚合函数
9 af:aggregate_func_name p=parameters
10 {
11 model = new AggregateFuncModel(af.getText(), AggregateFuncModel.NO_FILTER);
12 model.setParameters(p);
13 }
14
15 //Normal functions普通函数
16 | f:function_name p=parameters
17 {
18 model = new FunctionModel(f.getText());
19 model.setParameters(p);
20 }
21
22 //Normal functions参数为空的普通函数[getdate()]
23 | #(FUNCTION_EMPTY_PARAM fun1:function_name)
24 {
25 model = new FunctionModel(fun1.getText());
26 }
27
28 //Normal functions参数为*的普通函数[now(*)
]
29 | #(FUNCTION_STAR_PARAM funStar:function_name)
30 {
31 model = new FunctionModel(funStar.getText());
32 express1.addOperator("*");
33 p = new ParametersModel();
34 p.addParameter(express1);
35 model.setParameters(p);
36 }
37
38 //Aggregate functions参数为*的COUNT函数,聚合函数[count(*)]
39 | #(FUNCTION_STAR_COUNT fun2:function_name)
40 {
41 model = new AggregateFuncModel(fun2.getText(), AggregateFuncModel.NO_FILTER);
42 express1.addOperator("*");
43 p = new ParametersModel();
44 p.addParameter(express1);
45 model.setParameters(p);
46 }
47
48 //Aggregate functions参数为全部、all的聚合函数
49 | #(all:"全部" af11:function_name p=parameters)
50 {
51 model = new AggregateFuncModel(af11.getText(), AggregateFuncModel.ALL);
52 model.setParameters(p);
53 }
54 | #("all" af12:function_name p=parameters)
55 {
56 model = new AggregateFuncModel(af12.getText(), AggregateFuncModel.ALL);
57 model.setParameters(p);
58 }
59
60 //Aggregate functions参数为唯一、distinct的聚合函数
61 | #(dist:"唯一" af21:function_name p=parameters)
62 {
63 model = new AggregateFuncModel(af21.getText(), AggregateFuncModel.DISTINCT);
64 model.setParameters(p);
65 }
66 | #("distinct" af22:function_name p=parameters)
67 {
68 model=new AggregateFuncModel(af22.getText(), AggregateFuncModel.DISTINCT);
69 model.setParameters(p);
70 }
71 ;
4、增加NoGroupExistsException异常类,用来存放SELECT字句中非聚合函数表达式却没有在GROUP BY出现的表达式
5、增加非聚合函数表达式对象UnAggregateExpVO,用来对存放单个字段的非聚合函数表达式。
6、修改了编译器模型对象QueryModel的parseQuery方法,修改思路如下:
①获取所有聚合函数表达式,存放在aFunMap的Map中,并设置是否存在标识(默认为不存在)
②获取SELECT子句的所有表达式,并与aFunMap的KEY进行比较,如果存在,则设置aFunMap的值为存在标识;如果不存在则放入nGroupExprMap的 Map中,如果此表达式为单个字段的表达式,则构造UnAggregateExpVO对象并同时放入mGroupSingleExprMap中。
③获取GROUP BY子句的所有表达式,并与nGroupExprMap比较,如果存在则设置为存在标识;如果不存在,与mGroupSingleExprMap比较,如果存在则设置此表达式标识也为存在
④遍历SELECT子句的所有非聚合函数表达式,如果其标识为不存在,则构造NoGroupExistsException并将此表达式放入异常集合中即可。
代码如下:
//==== SELECT子句中非聚合函数表达式必须在GROUP BY子句中出现 BEGIN ====//
Map aFunMap = new LinkedHashMap(); //聚合函数Map
//获取所有聚合函数Model数组
QueryModel[] _aggregateFunModelArr = model.getModelsFromAllChildrenByClass(AggregateFuncModel.class);
if (_aggregateFunModelArr.length > 0){ //如果存在聚合函数
// 循环获取所有聚合函数Model数组相关信息
for (int i = 0; i < _aggregateFunModelArr.length; i++) {
aFunMap.put(_aggregateFunModelArr[i].getChString(), IS_NOT_EXISTS); //将聚合函数放入Map中,标识为IS_NOT_EXISTS
//QueryModel apm = _aggregateFunModelArr[i].getFirstModelByClass(ParametersModel.class);
// 得到每个集合函数的所有参数表达式模型
//QueryModel expm = apm.getFirstModelByClass(ExpressionModel.class);
//QueryModel[] expms = apm.getModelByClass(ExpressionModel.class);
// 得到每个集合函数的所有字段模型
//QueryModel[] fdms = apm.getModelsFromAllChildrenByClass(FieldModel.class);
}
Map nGroupExprMap = new LinkedHashMap(); //需要在分组出现的表达式Map
Map mGroupSingleExprMap = new LinkedHashMap(); //可分组出现的单个表达式Map
//获取SELECT子句下的所有表达式
QueryModel[] _columnModelArr = model.getModelsFromAllChildrenByClass(ColumnModel.class);
for (int i = 0; i < _columnModelArr.length; i++){
ColumnModel _columnModel = (ColumnModel) _columnModelArr[i];
QueryModel expm = _columnModel.getFirstModelByClass(ExpressionModel.class); //获取ColumnModel的表达式
if (!((ExpressionModel)expm).hasConstant()){ //如果不是常量则与带有聚合函数的表达式进行比较(目前abs(-900)认为不是常量)
if (aFunMap.containsKey(expm.getChString())){
aFunMap.put(expm.getChString(), IS_EXISTS); //表示此聚合函数已在SELECT子句中找到
}else{
//获取此表达式的单个字段,如果为1个,则放入mGroupSingleExprMap中
QueryModel[] fmArr = expm.getModelsFromAllChildrenByClass(FieldModel.class);
if (fmArr.length == 1){
UnAggregateExpVO unAggregateExpVO = new UnAggregateExpVO();
unAggregateExpVO.setUnAggregateExp(expm.getChString());
unAggregateExpVO.setSingleExp(fmArr[0].getChString());
unAggregateExpVO.setExistsFlag(IS_NOT_EXISTS);
mGroupSingleExprMap.put(fmArr[0].getChString(), unAggregateExpVO);
nGroupExprMap.put(expm.getChString(), IS_NOT_EXISTS); //表示此KEY需要在分组中出现
}else if (fmArr.length == 0){
QueryModel[] smArr = expm.getModelsFromAllChildrenByClass(StringModel.class);
if (smArr.length != 1){ //如果表达式不存在单个常量(如: abs(-9000))
nGroupExprMap.put(expm.getChString(), IS_NOT_EXISTS); //表示此KEY需要在分组中出现
}
}else{
nGroupExprMap.put(expm.getChString(), IS_NOT_EXISTS); //表示此KEY需要在分组中出现
}
}
}
}
//获取GROUP BY列表模型对象
QueryModel _groupByListModel = model.getFirstModelByClass(AggregateExprListModel.class);
//获取GROUP BY列表中所有表达式数组
QueryModel[] _groupByExprModelArr;
if (_groupByListModel == null){
_groupByExprModelArr = new QueryModel[0];
}else{
_groupByExprModelArr = _groupByListModel.getModelByClass(AggregateExprModel.class);
}
//如果GROUP BY列表中的表达式在SELECT字句的需分组的Map(nGroupExprMap)中存在,则设置存在标识
for (int i = 0; i < _groupByExprModelArr.length; i++){
if (nGroupExprMap.containsKey(_groupByExprModelArr[i].getChString())){
nGroupExprMap.put(_groupByExprModelArr[i].getChString(), IS_EXISTS);
}else if (mGroupSingleExprMap.containsKey(_groupByExprModelArr[i].getChString())){
//判断此表达式的单个字段是否出现,如果在分组中出现,则设置存在标识
UnAggregateExpVO unAggregateExpVO = (UnAggregateExpVO) mGroupSingleExprMap.get(_groupByExprModelArr[i].getChString());
nGroupExprMap.put(unAggregateExpVO.getUnAggregateExp(), IS_EXISTS);
}
}
//循环获取需分组的Map(nGroupExprMap)中,在GROUP BY没出现的SELECT表达式则放入编译器异常集合中
for (Iterator it = nGroupExprMap.keySet().iterator(); it.hasNext();){
String selectExpr = (String) it.next();
if (((String)nGroupExprMap.get(selectExpr)).equals(IS_NOT_EXISTS)){
NoGroupExistsException _exception = new NoGroupExistsException(selectExpr);
exs.add(_exception);
}
}
// 得到所有函数模型(包括一般函数和聚合函数)--此函数会带有GROUP BY中的函数
//QueryModel[] _allFunctionModelArr = model.getModelsFromAllChildrenByClass(FunctionModel.class);
}
//====SELECT子句中非聚合函数表达式必须在GROUP BY子句中出现 END ===//
LORD
jiandeh@sina.com2007-05-22
posted on 2007-05-22 11:55
LORD BLOG 阅读(1039)
评论(0) 编辑 收藏 所属分类:
工作日志