基本思想:
1。对简单的sql语句,类似select A.a, B.b from A, B left join C on b.b = C.c where ...
这种不包含子查询,没有union/minus进行关联的语句,只要根据关键词来分析就行了。先把他们join替换成‘,’以便统一分析。从而将问题简化为解析from关键词后面的table名字,多表的话,一定是用','隔开的,这样就好分析了。
2。对于包含子查询,union/minus来关联的语句,把他们先分解成两部分,除去子查询或者union/minus关联的那部分,属于简单sql语句,用方法1就行了。对于子查询或者union/minus关联的那部分,采用递归。最终还是化解到方法1莱解决。
3。对于子查询,需要递归到下一层,那么在当前这一层,用subTable来进行替代,以保证当前简单sql语句的完整性。最后统计table的时候,对于subTable就不算进去了。
详细见一下代码:
package com.sqlparser;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashSet;
import java.util.Iterator;
public class TableQuerier {
public static String startKey = "SELECT ";
public static String fromKey = " FROM ";
public static String joinKey = " JOIN ";
public static String onKey = " ON ";
public static String endKey = " WHERE ";
public static String unionKey = " UNION ";
public static String minusKey = " MINUS ";
public String subTable = "subTable";
private HashSet tableSet;
private String fileName;
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TableQuerier tq = new TableQuerier("c://data.txt");
HashSet s = tq.getTableSet();
tq.parseTableFromFile();
Iterator i = s.iterator();
System.out.println("The following tables are included in this sql statement.");
int num = 1;
System.out.println("Number# tableName");
while(i.hasNext()){
System.out.println(num+" "+i.next());
num++;
}
}
public void parseTableFromFile(){
BufferedReader buf = null;
try {
buf = new BufferedReader(new FileReader(fileName));
String line = buf.readLine();
StringBuilder sb = new StringBuilder();
while(line != null){
sb.append(line.toUpperCase()+" ");
line = buf.readLine();
}
//System.out.println(sb.toString());
getLevelOneTables(sb.toString(), tableSet);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
try {
buf.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public TableQuerier(String fileName){
tableSet = new HashSet();
this.fileName = fileName;
}
public void getLevelOneTables(String str, HashSet s){
if("".equals(str)){
return;
}
//remove sub query
int firstLeftBlockPos = str.indexOf("(");
int lastRightBlockPos = -1;
while(firstLeftBlockPos != -1){
//get matched ')', remove the substring between them
int leftBlockNum = 1;
for(int start = firstLeftBlockPos +1; start < str.length(); start++){
if(str.charAt(start) == ')'){
if(leftBlockNum == 1){
lastRightBlockPos = start;
break;
}else{
leftBlockNum --;
}
}else if(str.charAt(start) == '('){
leftBlockNum ++;
}
}
if(lastRightBlockPos < 0){
try {
throw new Exception("block mismatch");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
String blockContent = str.substring(firstLeftBlockPos+1, lastRightBlockPos);
//parse the content in block
if(blockContent.contains(startKey)){
getLevelOneTables(blockContent, s);
str = str.substring(0,firstLeftBlockPos)+" "+subTable+" "+str.substring(lastRightBlockPos+1);
}else{//remove '(' and ')' at level one
str = str.substring(0,firstLeftBlockPos)
+str.substring(firstLeftBlockPos+1,lastRightBlockPos)
+str.substring(lastRightBlockPos +1);
}
firstLeftBlockPos = str.indexOf("(");
}
//if the statement is joined with 'UNION' or 'MINUS',
//parse the first segement left of the key word('UNION' or 'MINUS')
int unionPos = -1;
int minusPos = -1;
int breakPos = -1;
unionPos = str.indexOf(unionKey);
minusPos = str.indexOf(minusKey);
if(unionPos != -1 ||minusPos != -1){
if(unionPos != -1 && minusPos != -1){
breakPos = minusPos < unionPos ? minusPos:unionPos;
}else{
breakPos = minusPos < unionPos ? unionPos:minusPos;
}
}
if(breakPos != -1){
String rightContent = str.substring(breakPos+unionKey.length()).trim();
rightContent = rightContent.startsWith("ALL")?rightContent.substring(3):rightContent;
getLevelOneTables(rightContent, s);
str = str.substring(0, breakPos).trim();
}
//change join to ','
// if join table
int joinKeyPos = str.indexOf(joinKey);
if(joinKeyPos != -1){
str = str.replace(joinKey, ",");
}
//now, we can look for tables in a simple statement
int fromPos = str.indexOf(fromKey);
int endPos = str.indexOf(endKey);
if(endPos == -1){
endPos = str.length();
}
if(fromPos > 0){
str = str.substring(fromPos+fromKey.length(), endPos).trim();
}else{
return;
}
//System.out.println("modified str = "+str);
String tableName = str.indexOf(" ") > 0?str.substring(0,str.indexOf(" ")).trim():str.trim();//the first word after 'from' is a table
if(!subTable.equals(tableName)){
s.add(tableName);
}
str = str.substring(str.indexOf(tableName)+tableName.length()).trim();
//if multiple table after 'from'
int dotIndex = str.indexOf(",");
while(dotIndex != -1){
str = str.substring(dotIndex+1).trim();
tableName = str.indexOf(" ")>0?str.substring(0,str.indexOf(" ")).trim():str.trim();//the first word after ',' must be a table name
if(!subTable.equals(tableName)){
s.add(tableName);
}
str = str.substring(str.indexOf(tableName)+tableName.length()).trim();
dotIndex = str.indexOf(",");
}
}
/**
* @return the fileName
*/
public String getFileName() {
return fileName;
}
/**
* @param fileName the fileName to set
*/
public void setFileName(String fileName) {
this.fileName = fileName;
}
/**
* @return the tableSet
*/
public HashSet getTableSet() {
return tableSet;
}
/**
* @param tableSet the tableSet to set
*/
public void setTableSet(HashSet tableSet) {
this.tableSet = tableSet;
}
}
这是针对一条sql语句的解析方法。下次有时间可以改进成针对存储过程,函数的解析方法。
未经大量测试,如果有bug请告知。谢谢:)
分享到:
相关推荐
模块6:缓存以及缓冲引擎,对于select语句,解析sql语句之前。mysqld先检查查询缓存区域,如果能够在其中找到对应的查询,服务器不会继续解析,而是直接返回查询缓存的内容直接返回。 模块7:可插拔的存储引擎,常用...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
[MonthMaker.java] 月份表算法类 [Pallet.java] 调色板,统一配色类 Java扫雷源码 Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP ...
[MonthMaker.java] 月份表算法类 [Pallet.java] 调色板,统一配色类 Java扫雷源码 Java生成自定义控件源代码 2个目标文件 Java实现HTTP连接与浏览,Java源码下载 1个目标文件 摘要:Java源码,网络相关,HTTP ...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
在数据仓库建设中,经常会使用到数据血缘追中方面的功能,本项目实现了对hql集合进行静态分析,获取hql对应的血缘图(表血缘 + 字段血缘) 项目升级内容 删除hive-exec与hadoop-common的maven依赖,使得项目更加的轻...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
SQL语句高效解析处理 数据权限模块的核心之一就有SQL语句的高效解析处理,SQL处 理指根据当前登录人信息及数据权限策略生成一个带有数据权限处 理结果的SQL语句,所以这里对SQL语句的解析处理必须要求精确、 准确。...
JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于...
使用PreparedStatement,动态执行sql语句,UsingPreparedStatement.java; 读写二进制数据,BinaryData.java; 读写Blob数据,blob数据常以二进制形式存储比较大的文件数据,如图片、视频文件等,本文介绍如何往...
Q0027 哪些SQL语句在执行时是自动提交的? 数据定义语言DDL是自动提交的。 Q0028 索引对数据库的影响? 提高查询速度 Q0029 主外键有什么关系? 外键是从某个表的一个字段指向另外一个表的主健字段,两个字段的类型...
|___GetSql.java 自动生成sql语句。在本框架中基本上不直接使用。 |___Hyberbin.java 进一步封装了数据库的操作,用户不直接对数据库操作,只要给出实体POJO类,数据可以自动查询、修改、删除、插入 servlet 用户...
通过阅读《SQL Server 2008查询性能优化》,不仅可以学习到数据库性能管理的许多知识和技巧,还有助于养成良好的编程习惯,为实现高性能的数据库应用系统打下基础。 目录 第1章 SQL查询性能调整 1 1.1 性能调整...