如坐春风
人生苦短,要紧跟自己的梦想,爱你所做的事业。
posts - 160,  comments - 284,  trackbacks - 0
下面是我在自己的一个项目中用来分析嵌套SQL语句的两个类,它们的基本做法就是靠括号来区别嵌套语句的层,然后用类似进栈的方法将复杂SQL分离成一个个小的简单SQL语句,最好再用类似出栈的方法将整个SQL整形好.

代码如下:
SqlFormatter类:
package com.junglesong.common.sqlFormatter;

import java.util.Hashtable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import com.junglesong.common.sqlFormatter.Exception.CantParseSqlException;
import com.junglesong.common.sqlFormatter.Exception.SingleKHException;

public class SqlFormatter {
    
private static final char LeftKH = '(';

    
private static final char RightKH = ')';

    
private static final String ReplacePart = "ReplacePart";

    
private Hashtable partialSqlMap;

    
public SqlFormatter() {
        partialSqlMap 
= new Hashtable();
    }


    
private void checkPairKuoHao(String sql) throws SingleKHException {
        
int retval = 0;
        
for (int i = 0; i < sql.length(); i++{
            
char tmp = sql.charAt(i);

            
if (tmp == LeftKH) {
                retval
++;
            }
 else if (tmp == RightKH) {
                retval
--;
            }

        }


        
if (retval != 0{
            
throw new SingleKHException(sql);
        }

    }


    
public String formatSql(String originalSql) throws SingleKHException,
            CantParseSqlException 
{
        checkPairKuoHao(originalSql);

        
int index = 0;
        
while (isFindKuohao(originalSql)) {
            
int leftKHPos = getDeepestLeftKHPos(originalSql);
            
int rightKHPos = getNearestRightKHPos(leftKHPos, originalSql);
            
int layer = getLeftKHLayer(leftKHPos, originalSql);

            String replacePart 
= originalSql.substring(leftKHPos,
                    rightKHPos 
+ 1);

            String replacePartIndex 
= ReplacePart + index;

            partialSqlMap.put(replacePartIndex, 
new PartialSql(replacePart,
                    layer));

            originalSql 
= originalSql.replace(replacePart, replacePartIndex);
            index
++;
        }


        String middleSql 
= new PartialSql(originalSql).getSql();

        String patternStr 
= "(" + ReplacePart + "[0-9]+)";
        Pattern pattern 
= Pattern.compile(patternStr);

        Matcher matcher 
= pattern.matcher(middleSql);

        
while (matcher.find()) {
            String replaceStr 
= matcher.group();
            PartialSql replacePart 
= (PartialSql) partialSqlMap.get(replaceStr);
            middleSql 
= middleSql.replace(replaceStr, replacePart.getSql());

            matcher 
= pattern.matcher(middleSql);
        }


        String finalSql 
= middleSql;

        
return finalSql;
    }


    
private boolean isFindKuohao(String text) {
        
return isFindLeftKh(text) || isFindRightKh(text);
    }


    
private boolean isFindLeftKh(String text) {
        
return text.indexOf(LeftKH) >= 0;
    }


    
private boolean isFindRightKh(String text) {
        
return text.indexOf(RightKH) >= 0;
    }


    
private int getDeepestLeftKHPos(String text) {
        
int retval = 0;
        
for (int i = 0; i < text.length(); i++{
            
char tmp = text.charAt(i);

            
if (tmp == LeftKH) {
                retval 
= i;
            }

        }


        
return retval;
    }


    
private int getNearestRightKHPos(int leftKHPos, String text)
            
throws SingleKHException {
        
int retval = 0;
        
for (int i = leftKHPos; i < text.length(); i++{
            
char tmp = text.charAt(i);

            
if (tmp == RightKH) {
                retval 
= i;
                
return retval;
            }

        }


        
throw new SingleKHException(text);
    }


    
private int getLeftKHLayer(int leftKHPos, String text) {
        
int retval = 0;
        
for (int i = 0; i < leftKHPos; i++{
            
char tmp = text.charAt(i);

            
if (tmp == LeftKH) {
                retval
++;
            }
 else if (tmp == RightKH) {
                retval
--;
            }

        }


        
return retval;
    }


    
public static void main(String[] args) {
        
try {
            
// String text = "select f1,(select a from b) from (select f1,f2
            
// from (select f1,f2,f3 from tb)),t4 where 1=1 ";

            
// String text = "select f1,f2,f3,f4,f5 from tabl1 where 1=1 ";
            
// String text = "select f1,(select f2 from t01) from t02 where 1=1
            
// ";
            
//String text = "select f1,(select * from tb2,(select * from (select * from tb4))) from tabl1 where 1=1 ";
            String text = "select f1,(select * from tb2,(select * from (select * from (select * from tb5)))) from tabl1 where 1=1 ";
            
            

            SqlFormatter testSqlParser 
= new SqlFormatter();

            System.out.println(
"Final Text=\n" + testSqlParser.formatSql(text));
        }
 catch (SingleKHException ex) {
            System.out.print(ex.getErrMsg());
        }
 catch (CantParseSqlException ex) {
            System.out.print(ex.getErrMsg());
        }
 catch (Exception ex) {
            ex.printStackTrace();
        }

    }

}

PartialSql类:
package com.junglesong.common.sqlFormatter;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

import com.junglesong.common.sqlFormatter.Exception.CantParseSqlException;

public class PartialSql {
    
private String sql;

    
private int layer;

    
private List sqlLines;

    
private static final String CRLF = "\n";

    
private static final String TAB = "    "// Four Spaces

    
public PartialSql(String sql, int layer) throws CantParseSqlException {
        
this.sql = removeKH(sql);
        
this.layer = layer;
        sqlLines 
= new ArrayList();
        splitSql(
this.sql);
    }


    
public PartialSql(String sql) throws CantParseSqlException {
        
this(sql, -1);
    }


    
private void splitSql(String sql) throws CantParseSqlException {
        
if(sql.toLowerCase().indexOf("select")<0){
            
throw new CantParseSqlException(sql);
        }

        
        
        
try {
            Pattern p 
= Pattern.compile("(select)|(from)|(where)",
                    Pattern.CASE_INSENSITIVE);
            String[] results 
= p.split(sql);

            String[] fields 
= null;
            String[] tables 
= null;
            String wherePart 
= "";

            
if (results.length == 4{
                fields 
= getSplitDotArray(results[1]);
                tables 
= getSplitDotArray(results[2]);
                wherePart 
= results[3];
            }
 else if (results.length == 3{
                fields 
= getSplitDotArray(results[1]);
                tables 
= getSplitDotArray(results[2]);
                wherePart 
= "";
            }


            String tab 
= TAB;

            sqlLines.add(
" Select " + tab + CRLF);
            
int n = fields.length;
            
for (int i = 0; i < n; i++{
                
if (i != n - 1{
                    sqlLines.add(tab 
+ tab + fields[i].trim() + "," + CRLF);
                }
 else {
                    sqlLines.add(tab 
+ tab + fields[i].trim() + CRLF);
                }

            }


            sqlLines.add(
" from   " + tab + CRLF);
            n 
= tables.length;
            
for (int i = 0; i < n; i++{
                
if (i != n - 1{
                    sqlLines.add(tab 
+ tab + tables[i].trim() + "," + CRLF);
                }
 else {
                    sqlLines.add(tab 
+ tab + tables[i].trim() + CRLF);
                }

            }


            
if (wherePart.length() > 0{
                sqlLines.add(
" where " + tab + CRLF);
                
                Pattern pattern 
= Pattern.compile("(and)",
                        Pattern.CASE_INSENSITIVE);
                String[] wheres 
= pattern.split(wherePart);
                
                n 
= wheres.length;
                
for (int i = 0; i < n; i++{
                    
if (i != n - 1{
                        sqlLines.add(tab 
+ tab + wheres[i].trim() + " and " + CRLF);
                    }
 else {
                        sqlLines.add(tab 
+ tab + wheres[i].trim() + CRLF);
                    }

                }

                
//sqlLines.add(tab + tab + wherePart);
            }

        }
 catch (Exception ex) {
            
throw new CantParseSqlException(sql);
        }

    }


    
private String[] getSplitDotArray(String text) {
        Pattern p 
= Pattern.compile("[,]");
        String[] results 
= p.split(text);

        
return results;
    }


    
private String removeKH(String sql) {
        String retval 
= sql;
        retval 
= retval.replace("(""");
        retval 
= retval.replace(")""");

        
return retval;
    }


    
public String getSql() {
        String retval 
= "";

        
if (layer != -1