2017-07-25 60 views
0

我知道通過使用準備語句我們可以設置列值。這裏我想要的是,我已經有一個查詢列表,寫在同一個表上執行,但具有不同的列值。例如。解析Java中的SQL查詢

select * from tableName as t1 where t1.tableColumnId=4 and t1.tableColumnName='test' inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId 

select * from tableName as t1 where t1.tableColumnId=6 and t1.tableColumnName='test' inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId 

正如你可以看到這兩個查詢是除了tableColumnId值幾乎相同。我想將它保存爲集合,因爲

select * from tableName as t1 where t1.tableColumnId=? and t1.tableColumnName='test' inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId 

這樣我就不會有重複查詢(其中不考慮值)。

我該怎麼做?

+1

使用prepared語句方法 –

+0

通過使用預處理語句,我們可以傳遞這些值,但是這裏我想用一些字符替換已存在於查詢中的值並將其存儲在集合中。請告訴我,如果我們可以使用preparedStatement來實現這一點。 – Jagadeeswar

回答

1
  1. 一種辦法將包括在定義SQL語法,這將是足以解析您的疑問,那麼寫的是語法解析器的一個子集,
  2. 比較查詢,發現是相同的部分,那些不同的,
  3. 在您的查詢中找到像4,,'test'這樣的文字值,構建(平坦)句法樹,並將這些樹相互比較以標識可能因查詢不同而不同的文字值。

UPDATE

爲了解析SQL,你可以像用戶或ANTLR一個JavaCC解析器生成。 SQL存在ANTLR和JavaCC語法,您可以從其中一個開始。

這就是說,我認爲這種做法在這種情況下是過分的;我寧願使用第三個。

更新2:(第三種方法)

要查找文本字符串和數字,你可以使用正則表達式:

private static final Pattern CONST_PATTERN 
     = Pattern.compile("([^0-9a-zA-Z])((?:[0-9]+(?:\\.[0-9]*)?|[0-9]*\\.[0-9]+)" 
       + "(?:[Ee][+-][0-9]+])?" 
       + "|(?:\\'[^']*\\')+)", Pattern.CASE_INSENSITIVE); 

您可以分析查詢而產生的結構如下:

private static class ParameterizedQuery { 
    final String sql; 
    final Parameter[] params; 

    ParameterizedQuery(String sql, Parameter[] params) { 
     this.sql = sql; 
     this.params = params.clone(); 
    } 
} 

private static class Parameter { 
    final int position; 
    final String value; 

    Parameter(int position, String value) { 
     this.position = position; 
     this.value = value; 
    } 
} 

生成的sql查詢是所有文字用問號替換的輸入查詢。 ,

private static ParameterizedQuery parse(String query) { 
    List<Parameter> parms = new ArrayList<>(); 
    Matcher matcher = CONST_PATTERN.matcher(query); 
    int start = 0; 
    StringBuilder buf = new StringBuilder(); 
    while (matcher.find()) { 
     int pos = matcher.start(); 
     buf.append(query, start, pos) 
       .append(matcher.group(1)) 
       .append("?"); 
     parms.add(new Parameter(buf.length()-1,matcher.group(2))); 
     start = matcher.end(); 
    } 
    buf.append(query, start, query.length()); 
    return new ParameterizedQuery(
      buf.toString(), parms.toArray(new Parameter[parms.size()])); 
} 

現在,如果你有疑問的列表,你想保持作爲參數只有那些不等於在所有的輸入查詢,您分析您所有的疑問,生產:解析完成如下ParameterizedQuery的陣列,並且簡化該數組:

private static ParameterizedQuery[] simplify(ParameterizedQuery[] queries) { 
    if (queries.length == 0) { 
     return queries; 
    } 
    ParameterizedQuery prev = null; 
    boolean[] diff = null; 
    for (ParameterizedQuery cur: queries) { 
     if (prev == null) { 
      diff = new boolean[cur.params.length]; 
     } else { 
      if (!cur.sql.equals(prev.sql)) { 
       throw new RuntimeException(
         "Queries are too different: [" + prev.sql 
         + "] and [" + cur.sql + "]"); 
      } else if (cur.params.length != prev.params.length) { 
       throw new RuntimeException(
         "Different number of parameters: [" 
         + prev.params.length 
         + "] and [" + cur.params.length + "]"); 
      } 
      for (int i = 0; i < diff.length; ++i) { 
       if (!cur.params[i].value.equals(prev.params[i].value)) { 
        diff[i] = true; 
       } 
      } 
     } 
     prev = cur; 
    } 
    if (and(diff)) { 
     return queries; 
    } 
    ParameterizedQuery[] result = new ParameterizedQuery[queries.length]; 
    result[0] = expandQuery(queries[0].sql, queries[0].params, diff); 
    for (int i = 1; i < queries.length; ++i) { 
     result[i] = new ParameterizedQuery(result[0].sql, 
       keep(queries[i].params, result[0].params, diff)); 
    } 
    return result; 
} 

private static boolean and(boolean[] arr) { 
    for (boolean b: arr) { 
     if (!b) { 
      return false; 
     } 
    } 
    return true; 
} 

private static ParameterizedQuery expandQuery(String query, 
     Parameter[] params, boolean[] diff) { 
    int count = 0; 
    for (boolean b: diff) { 
     if (b) { 
      ++count; 
     } 
    } 
    Parameter[] result = new Parameter[count]; 
    int r = 0; 
    int start = 0; 
    StringBuilder buf = new StringBuilder(); 
    for (int i = 0; i < diff.length; ++i) { 
     Parameter parm = params[i]; 
     if (!diff[i]) { 
      // expand param 
      buf.append(query, start, parm.position); 
      buf.append(parm.value); 
      start = parm.position+1; 
     } else { 
      buf.append(query, start, parm.position); 
      result[r++] = new Parameter(buf.length(), parm.value); 
      start = parm.position; 
     } 
    } 
    buf.append(query, start, query.length()); 
    return new ParameterizedQuery(buf.toString(), result); 
} 

private static Parameter[] keep(Parameter[] params, Parameter[] ref, 
     boolean[] diff) { 
    Parameter[] result = new Parameter[ref.length]; 
    int j = 0; 
    for (int i = 0; i < params.length; ++i) { 
     if (diff[i]) { 
      result[j] = new Parameter(ref[j].position, params[i].value); 
      ++j; 
     } 
    } 
    return result; 
} 

下面是解決您的示例方案:

public class Main { 
    private static final String[] QUERIES = { 
     "select * from tableName as t1 where t1.tableColumnId=4 and t1.tableColumnName='test' inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId", 
     "select * from tableName as t1 where t1.tableColumnId=6 and t1.tableColumnName='test' inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId", 
    }; 
    private static final Pattern CONST_PATTERN 
      = Pattern.compile("([^0-9a-zA-Z])((?:[0-9]+(?:\\.[0-9]*)?|[0-9]*\\.[0-9]+)" 
        + "(?:[Ee][+-][0-9]+])?" 
        + "|(?:\\'[^']*\\')+)", Pattern.CASE_INSENSITIVE); 

    private static class ParameterizedQuery { 
     final String sql; 
     final Parameter[] params; 

     ParameterizedQuery(String sql, Parameter[] params) { 
      this.sql = sql; 
      this.params = params.clone(); 
     } 
    } 

    private static class Parameter { 
     final int position; 
     final String value; 

     Parameter(int position, String value) { 
      this.position = position; 
      this.value = value; 
     } 
    } 

    public static void main(String[] args) { 
     ParameterizedQuery[] queries = new ParameterizedQuery[QUERIES.length]; 
     for (int i = 0; i < QUERIES.length; ++i) { 
      queries[i] = parse(QUERIES[i]); 
     } 
     for (ParameterizedQuery cur: queries) { 
      System.out.println(cur.sql); 
      int i = 0; 
      for (Parameter parm: cur.params) { 
       System.out.println(" " + (++i) + ": " + parm.value); 
      } 
     } 
     queries = simplify(queries); 
     for (ParameterizedQuery cur: queries) { 
      System.out.println(cur.sql); 
      int i = 0; 
      for (Parameter parm: cur.params) { 
       System.out.println(" " + (++i) + ": " + parm.value); 
      } 
     } 
    } 

    private static ParameterizedQuery parse(String query) { 
     List<Parameter> parms = new ArrayList<>(); 
     Matcher matcher = CONST_PATTERN.matcher(query); 
     int start = 0; 
     StringBuilder buf = new StringBuilder(); 
     while (matcher.find()) { 
      int pos = matcher.start(); 
      buf.append(query, start, pos) 
        .append(matcher.group(1)) 
        .append("?"); 
      parms.add(new Parameter(buf.length()-1,matcher.group(2))); 
      start = matcher.end(); 
     } 
     buf.append(query, start, query.length()); 
     return new ParameterizedQuery(
       buf.toString(), parms.toArray(new Parameter[parms.size()])); 
    } 

    private static ParameterizedQuery[] simplify(ParameterizedQuery[] queries) { 
     if (queries.length == 0) { 
      return queries; 
     } 
     ParameterizedQuery prev = null; 
     boolean[] diff = null; 
     for (ParameterizedQuery cur: queries) { 
      if (prev == null) { 
       diff = new boolean[cur.params.length]; 
      } else { 
       if (!cur.sql.equals(prev.sql)) { 
        throw new RuntimeException(
          "Queries are too different: [" + prev.sql 
          + "] and [" + cur.sql + "]"); 
       } else if (cur.params.length != prev.params.length) { 
        throw new RuntimeException(
          "Different number of parameters: [" 
          + prev.params.length 
          + "] and [" + cur.params.length + "]"); 
       } 
       for (int i = 0; i < diff.length; ++i) { 
        if (!cur.params[i].value.equals(prev.params[i].value)) { 
         diff[i] = true; 
        } 
       } 
      } 
      prev = cur; 
     } 
     if (and(diff)) { 
      return queries; 
     } 
     ParameterizedQuery[] result = new ParameterizedQuery[queries.length]; 
     result[0] = expandQuery(queries[0].sql, queries[0].params, diff); 
     for (int i = 1; i < queries.length; ++i) { 
      result[i] = new ParameterizedQuery(result[0].sql, 
        keep(queries[i].params, result[0].params, diff)); 
     } 
     return result; 
    } 

    private static boolean and(boolean[] arr) { 
     for (boolean b: arr) { 
      if (!b) { 
       return false; 
      } 
     } 
     return true; 
    } 

    private static ParameterizedQuery expandQuery(String query, 
      Parameter[] params, boolean[] diff) { 
     int count = 0; 
     for (boolean b: diff) { 
      if (b) { 
       ++count; 
      } 
     } 
     Parameter[] result = new Parameter[count]; 
     int r = 0; 
     int start = 0; 
     StringBuilder buf = new StringBuilder(); 
     for (int i = 0; i < diff.length; ++i) { 
      Parameter parm = params[i]; 
      if (!diff[i]) { 
       // expand param 
       buf.append(query, start, parm.position); 
       buf.append(parm.value); 
       start = parm.position+1; 
      } else { 
       buf.append(query, start, parm.position); 
       result[r++] = new Parameter(buf.length(), parm.value); 
       start = parm.position; 
      } 
     } 
     buf.append(query, start, query.length()); 
     return new ParameterizedQuery(buf.toString(), result); 
    } 

    private static Parameter[] keep(Parameter[] params, Parameter[] ref, 
      boolean[] diff) { 
     Parameter[] result = new Parameter[ref.length]; 
     int j = 0; 
     for (int i = 0; i < params.length; ++i) { 
      if (diff[i]) { 
       result[j] = new Parameter(ref[j].position, params[i].value); 
       ++j; 
      } 
     } 
     return result; 
    } 
} 

的輸出是:

select * from tableName as t1 where t1.tableColumnId=? and t1.tableColumnName=? inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId 
    1: 4 
    2: 'test' 
select * from tableName as t1 where t1.tableColumnId=? and t1.tableColumnName=? inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId 
    1: 6 
    2: 'test' 
select * from tableName as t1 where t1.tableColumnId=? and t1.tableColumnName='test' inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId 
    1: 4 
select * from tableName as t1 where t1.tableColumnId=? and t1.tableColumnName='test' inner join tableName2 as t2 on t1.tableColumnId=t2.tableColumnId 
    1: 6 
+0

感謝您的建議。你能告訴我如何在java中定義語法。 – Jagadeeswar

+0

@Jagadeeswar看到我的更新 –

+0

它的工作,非常感謝。 – Jagadeeswar