問題描述:
由于在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 閱讀(1044)
評論(0) 編輯 收藏 所屬分類:
工作日志