最近要实现一个简易的数据库系统,除了要考虑如何高效的存储和访问数据,建立表关系外,对基本的sql查询语句要做一个解析,这样我们才能知道用户的查询要求;因为时间关系,参考了已有的一篇文章,并对其实现中出的小问题给予更正,在这里跟大家共享一下。原文请查阅http://www.cnblogs.com/pelephone/articles/sql-parse-single-word.html

第一步:先对sql语句进行预处理;

对于用户,我们应该接受各种形式的查询语句书写,单行或者多行,语句中单个空格或者多个空格的间隔等等。但是我们要解析sql语句,就首先要让对它们做标准化,这样才能进行我们下一步处理。系统中的处理要求:

1)消除SQL语句前后的空白,将其中的连续空白字符(包括空格,TAB和回车换行)替换成单个空格;

2)将sql语句全变成小写形式(或大写形式);

3)在SQL语句的尾后加上结束符号“ENDOFSQL”(原因后面解释)

例如:用户输入:“select c1,c2,c3 from  t1,t2, t3 where condi1=5 and condi6=6 or condi7=7 order

by g1,g2”

通过预处理应该为:“select c1,c2,c3 from t1,t2,t3 where condi1=5 and condi6=6 or condi7=7 order by g1,g2”

第二步:将查询语句切分为语句块;

以查询语句为例(本文中主要是以查询语句作为例子讲解,其它删除,插入等语句原理于此类似,因为查询语句相对复杂,所以用来i讲解),正如上面我们标准化后的语句一样,我们要进行下一步的,对表中数据的处理,首先要知道是对那些表处理,要满足那些条件,输出那些属性,以什么顺序输出等。所以查询语句就可以分割为以下几个块:

1)select c1,c2,c3 from:属性输出块;块头(start)select,块尾(end)from,这个块我们关心的信息(body):c1,c2,c3;以下块类似分析

2)from....where; 涉及数据表块。

3)where.....order by; 查询条件块。

4)order by.....ENDOFSQL; 属性输出顺序。这里也就看出了我们为什么要在查询语句末尾加上结束符,是为了最后一个块的限定需要。

知道了如何分块,接下来要做的就是在我们已经标准化的sql语句上进行块的切割,这里我们用到了正则表达式,以第二个块from....where的查询为例,我们做个分析

"(from)(.+)( where | on | having | group by | order by | ENDOFSQL)“

以上就是第二个块的正则匹配式(其它块的匹配式下面也会给出),可以看出,在一个sql查询语句中,from块中跟from搭配出现的不只是where,还可以是on,having,group by等,那么通过这个正则式我们可以得到如下的块:

from .... where

from .... on

from .... having

from .... group by

from .... order by

from .... ENDOFSQL

这里我们要注意一点,就是在通过正则式对sql语句进行匹配时,我们不能对整个sql语句进行一次匹配操作,因为正则匹配是贪心匹配,它总是尽可能的向后查找,匹配到最大的语句段。就拿上述语句为例,如果通过对整个sql语句进行一次匹配,得到的就不是from....where这个语句段而是from .... where .... order by。显然这不是我们想要的。所以我们只能牺牲效率,通过对整个sql语句进行逐次递增的查询方式来查找相应的语句块。给出一个查询过程,加强理解,以上述sql语句为例,对第一个语句块的查找过程是

s

se

sel

sele

selec

select

select

select c

select c1

select c1,

select c1,c

select c1,c2

select c1,c2,

select c1,c2,c

select c1,c2,c3

select c1,c2,c3

select c1,c2,c3 f

select c1,c2,c3 fr

select c1,c2,c3 fro

select c1,c2,c3 from

这样就找到第一个块,以此类推,找第二个块时候又从头逐次递增查找。

第三步:找到了各个块,我们还要把我们最关心的信息提取出来,就是夹在语句块头和尾之间的body部分,这个就好实现了,一般的sql语句中都会用逗号来做分割,我们提取出各个块的body信息。

步骤介绍完了,下面就上代码,享乐吧...少年!

package com.sitinspring.common.sqlparser.single;

import java.util.List;

/** *//*** 单句Sql解析器制造工厂

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class SqlParserUtil{

/** *//*** 方法的主要入口

*@paramsql:要解析的sql语句

*@return返回解析结果*/

public String getParsedSql(String sql){

sql=sql.trim();

sql=sql.toLowerCase();

sql=sql.replaceAll("\\s{1,}", " ");

sql=""+sql+" ENDOFSQL";

//System.out.println(sql);

return SingleSqlParserFactory.generateParser(sql).getParsedSql();

}

/** *//*** SQL语句解析的接口

*@paramsql:要解析的sql语句

*@return返回解析结果*/

public List getParsedSqlList(String sql)

{

sql=sql.trim();

sql=sql.toLowerCase();

sql=sql.replaceAll("\\s{1,}", " ");

sql=""+sql+" ENDOFSQL";

//System.out.println(sql);

return SingleSqlParserFactory.generateParser(sql).RetrunSqlSegments();

}

}

package com.sitinspring.common.sqlparser.single;

//import com.sitinspring.common.sqlparser.single.NoSqlParserException;

import java.util.ArrayList;

import java.util.List;

import com.sitinspring.common.sqlparser.single.SqlSegment;

/** *//*** 单句Sql解析器,单句即非嵌套的意思

*@author赵朝峰()

*

*@since2013-6-10

*@version1.00*/

public abstract class BaseSingleSqlParser{

/** *//*** 原始Sql语句*/

protected String originalSql;

/** *//*** Sql语句片段*/

protected List segments;

/** *//*** 构造函数,传入原始Sql语句,进行劈分。

*@paramoriginalSql*/

public BaseSingleSqlParser(String originalSql){

this.originalSql=originalSql;

segments=new ArrayList();

initializeSegments();

splitSql2Segment();

}

/** *//*** 初始化segments,强制子类实现

**/

protected abstract void initializeSegments();

/** *//*** 将originalSql劈分成一个个片段

**/

protected void splitSql2Segment() {

for(SqlSegment sqlSegment:segments)

{

sqlSegment.parse(originalSql);

}

}

/** *//*** 得到解析完毕的Sql语句

*@return

*/

public String getParsedSql() {

//测试输出各个片段的信息

/*for(SqlSegment sqlSegment:segments)

{

String start=sqlSegment.getStart();

String end=sqlSegment.getEnd();

System.out.println(start);

System.out.println(end);

}*/

StringBuffer sb=new StringBuffer();

for(SqlSegment sqlSegment:segments)

{

sb.append(sqlSegment.getParsedSqlSegment());

}

String retval=sb.toString().replaceAll("@+", "\n");

return retval;

}

/** *//*** 得到解析的Sql片段

*@return

*/

public List RetrunSqlSegments()

{

int SegmentLength=this.segments.size();

if(SegmentLength!=0)

{

List result=this.segments;

return result;

}

else

{

//throw new Exception();

return null;

}

}

}

package com.sitinspring.common.sqlparser.single;

import com.sitinspring.common.sqlparser.single.SqlSegment;

/** *//***

* 单句删除语句解析器

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class DeleteSqlParser extends BaseSingleSqlParser{

public DeleteSqlParser(String originalSql) {

super(originalSql);

}

@Override

protected void initializeSegments() {

segments.add(new SqlSegment("(delete from)(.+)( where | ENDOFSQL)","[,]"));

segments.add(new SqlSegment("(where)(.+)( ENDOFSQL)","(and|or)"));

}

}

package com.sitinspring.common.sqlparser.single;

import com.sitinspring.common.sqlparser.single.SqlSegment;

/** *//***

* 单句查询插入语句解析器

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class InsertSelectSqlParser extends BaseSingleSqlParser{

public InsertSelectSqlParser(String originalSql) {

super(originalSql);

}

@Override

protected void initializeSegments() {

segments.add(new SqlSegment("(insert into)(.+)( select )","[,]"));

segments.add(new SqlSegment("(select)(.+)(from)","[,]"));

segments.add(new SqlSegment("(from)(.+)( where | on | having | groups+by | orders+by | ENDOFSQL)","(,|s+lefts+joins+|s+rights+joins+|s+inners+joins+)"));

segments.add(new SqlSegment("(where|on|having)(.+)( groups+by | orders+by | ENDOFSQL)","(and|or)"));

segments.add(new SqlSegment("(groups+by)(.+)( orders+by| ENDOFSQL)","[,]"));

segments.add(new SqlSegment("(orders+by)(.+)( ENDOFSQL)","[,]"));

}

}

package com.sitinspring.common.sqlparser.single;

import com.sitinspring.common.sqlparser.single.SqlSegment;

/** *//***

* 单句插入语句解析器

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class InsertSqlParser extends BaseSingleSqlParser{

public InsertSqlParser(String originalSql) {

super(originalSql);

}

@Override

protected void initializeSegments() {

segments.add(new SqlSegment("(insert into)(.+)([(])","[,]"));

segments.add(new SqlSegment("([(])(.+)( [)] values )","[,]"));

segments.add(new SqlSegment("([)] values [(])(.+)( [)])","[,]"));

}

@Override

public String getParsedSql() {

String retval=super.getParsedSql();

retval=retval+")";

return retval;

}

}

package com.sitinspring.common.sqlparser.single;

public class NoSqlParserException extends Exception{

private static final long serialVersionUID = 1L;

NoSqlParserException()

{

}

NoSqlParserException(String sql)

{

//调用父类方法

super(sql);

}

}

package com.sitinspring.common.sqlparser.single;

import com.sitinspring.common.sqlparser.single.SqlSegment;

/** *//***

* 单句查询语句解析器

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class SelectSqlParser extends BaseSingleSqlParser{

public SelectSqlParser(String originalSql) {

super(originalSql);

}

@Override

protected void initializeSegments() {

segments.add(new SqlSegment("(select)(.+)(from)","[,]"));

segments.add(new SqlSegment("(from)(.+)( where | on | having | group by | order by | ENDOFSQL)","(,| left join | right join | inner join )"));

segments.add(new SqlSegment("(where|on|having)(.+)( group by | order by | ENDOFSQL)","(and|or)"));

segments.add(new SqlSegment("(group by)(.+)( order by| ENDOFSQL)","[,]"));

segments.add(new SqlSegment("(order by)(.+)( ENDOFSQL)","[,]"));

}

}

package com.sitinspring.common.sqlparser.single;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

//import com.sitinspring.common.sqlparser.single.NoSqlParserException;/** *//*** 单句Sql解析器制造工厂

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class SingleSqlParserFactory{

public static BaseSingleSqlParser generateParser(String sql)

{

if(contains(sql,"(insert into)(.+)(select)(.+)(from)(.+)"))

{

return new InsertSelectSqlParser(sql);

}

else if(contains(sql,"(select)(.+)(from)(.+)"))

{

return new SelectSqlParser(sql);

}

else if(contains(sql,"(delete from)(.+)"))

{

return new DeleteSqlParser(sql);

}

else if(contains(sql,"(update)(.+)(set)(.+)"))

{

return new UpdateSqlParser(sql);

}

else if(contains(sql,"(insert into)(.+)(values)(.+)"))

{

return new InsertSqlParser(sql);

}

//sql=sql.replaceAll("ENDSQL", "");

else

return new InsertSqlParser(sql);

//throw new NoSqlParserException(sql.replaceAll("ENDOFSQL", ""));//对异常的抛出

}

/** *//*** 看word是否在lineText中存在,支持正则表达式

*@paramsql:要解析的sql语句

*@paramregExp:正则表达式

*@return

*/

private static boolean contains(String sql,String regExp){

Pattern pattern=Pattern.compile(regExp,Pattern.CASE_INSENSITIVE);

Matcher matcher=pattern.matcher(sql);

return matcher.find();

}

}

package com.sitinspring.common.sqlparser.single;

import java.util.ArrayList;

import java.util.List;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

/** *//*** Sql语句片段

*

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class SqlSegment{

private static final String Crlf = "@";

private static final String FourSpace = "  ";

/** *//*** Sql语句片段开头部分*/

private String start;

/** *//*** Sql语句片段中间部分*/

private String body;

/** *//*** Sql语句片段结束部分*/

private String end;

/** *//*** 用于分割中间部分的正则表达式*/

private String bodySplitPattern;

/** *//*** 表示片段的正则表达式*/

private String segmentRegExp;

/** *//*** 分割后的Body小片段*/

private List bodyPieces;

/** *//*** 构造函数

*@paramsegmentRegExp 表示这个Sql片段的正则表达式

*@parambodySplitPattern 用于分割body的正则表达式*/

public SqlSegment(String segmentRegExp,String bodySplitPattern){

start="";

body="";

end="";

this.segmentRegExp=segmentRegExp;

this.bodySplitPattern=bodySplitPattern;

this.bodyPieces=new ArrayList();

}

/** *//*** 从sql中查找符合segmentRegExp的部分,并赋值到start,body,end等三个属性中

*@paramsql*/

public void parse(String sql){

Pattern pattern=Pattern.compile(segmentRegExp,Pattern.CASE_INSENSITIVE);

for(int i=0;i<=sql.length();i++)

{

String shortSql=sql.substring(0, i);

//测试输出的子句是否正确

System.out.println(shortSql);

Matcher matcher=pattern.matcher(shortSql);

while(matcher.find())

{

start=matcher.group(1);

body=matcher.group(2);

//测试body部分//System.out.println(body);

end=matcher.group(3);

//测试相应的end部分//System.out.println(end);

parseBody();

return;

}

}

}

/** *//*** 解析body部分

**/

private void parseBody(){

List ls=new ArrayList();

Pattern p = Pattern.compile(bodySplitPattern,Pattern.CASE_INSENSITIVE);

//先清除掉前后空格

body=body.trim();

Matcher m = p.matcher(body);

StringBuffer sb = new StringBuffer();

boolean result = m.find();

while(result)

{

m.appendReplacement(sb, m.group(0) + Crlf);

result = m.find();

}

m.appendTail(sb);

//再按空格断行

String[] arr=sb.toString().split(" ");

int arrLength=arr.length;

for(int i=0;i

{

String temp=FourSpace+arr[i];

if(i!=arrLength-1)

{

//temp=temp+Crlf;

}

ls.add(temp);

}

bodyPieces=ls;

}

/** *//*** 取得解析好的Sql片段

*@return

*/

public String getParsedSqlSegment(){

StringBuffer sb=new StringBuffer();

sb.append(start+Crlf);

for(String piece:bodyPieces)

{

sb.append(piece+Crlf);

}

return sb.toString();

}

public String getBody()

{

return body;

}

public void setBody(String body)

{

this.body=body;

}

public String getEnd()

{

return end;

}

public void setEnd(String end)

{

this.end=end;

}

public String getStart()

{

return start;

}

public void setStart(String start)

{

this.start=start;

}

}

package com.sitinspring.common.sqlparser.single;

import com.sitinspring.common.sqlparser.single.SqlSegment;

/** *//***

* 单句更新语句解析器

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public class UpdateSqlParser extends BaseSingleSqlParser{

public UpdateSqlParser(String originalSql) {

super(originalSql);

}

@Override

protected void initializeSegments() {

segments.add(new SqlSegment("(update)(.+)(set)","[,]"));

segments.add(new SqlSegment("(set)(.+)( where | ENDOFSQL)","[,]"));

segments.add(new SqlSegment("(where)(.+)( ENDOFSQL)","(and|or)"));

}

}

执行结果:自己写了个测试的类

import java.util.List;

import com.sitinspring.common.sqlparser.single.*;

public class Test {

/** *//*** 单句Sql解析器制造工厂

*@author赵朝峰

*

*@since2013-6-10

*@version1.00*/

public static void main(String[] args) {

//TODO Auto-generated method stub//String test="select a from b " +//"\n"+"where a=b";//test=test.replaceAll("\\s{1,}", " ");//System.out.println(test);//程序的入口

String testSql="select c1,c2,c3 from t1,t2 where condi3=3 "+"\n"+" or condi4=5 order by o1,o2";

SqlParserUtil test=new SqlParserUtil();

String result=test.getParsedSql(testSql);

System.out.println(result);

//List result=test.getParsedSqlList(testSql);//保存解析结果

}

}

结果为

select

c1,

c2,

c3

from

t1,

t2

where

condi3=3

or

condi4=5

order by

o1,

o2

java sql语句逗号_Java 实现对Sql语句解析相关推荐

  1. sql java 解析_Java 实现对Sql语句解析

    最近要实现一个简易的数据库系统,除了要考虑如何高效的存储和访问数据,建立表关系外,对基本的sql查询语句要做一个解析,这样我们才能知道用户的查询要求:因为时间关系,参考了已有的一篇文章,并对其实现中出 ...

  2. java字符串字典排序_java实现对map的字典序排序操作示例

    本文实例讲述了java实现对map的字典序排序操作.分享给大家供大家参考,具体如下: java中对map的字典序排序,算法验证比对微信官网https://mp.weixin.qq.com/wiki?t ...

  3. java读取bmp图像_JAVA实现对BMP图片的读取

    BMP图片格式,是windows自带的一个图片格式,(*bmp),在windows的系统下都支持这种格式,bmp格式与设备无关的位图(DIB)格式,BMP简称位图,BMP的原始数据是没有经过压缩处理的 ...

  4. Asp代码转换java代码器_asp下实现对HTML代码进行转换的函数

    asp下实现对HTML代码进行转换的函数 更新时间:2007年08月08日 12:08:49   作者: '****************************** '函数:HTMLEncode( ...

  5. java与sql2005连接数据库_Java链接数据库SQl Server2005

    Java链接数据库SQL Server2005步骤: 1.到微软官方网站下载2005的jdbc并解压,获得文件sqljdbc.jar.本人使用的是sqljdbc_1.2,解压后即为该文件. sql j ...

  6. Red Gate - SQL Source Control实现对SQL SERVER 的源代码控制

    原文地址:http://bbs.csdn.net/topics/350165431 SQL Server 一直没有一款很好的源码控制器,之前自己曾尝试自己写一个,将所有的 脚本 自动生成到某一目录下, ...

  7. java循环基础知识_Java基础知识·循环语句

    掘友们,大家好呀,我是宸道. 今天要讲解的是Java基础的循环语句,虽然很基础但还是希望大家看完,就当时复习知识了,基础越牢固越好,对我们是有很大帮助的. 相关推荐 循环语句可以在满足循环条件的情况下 ...

  8. java 嵌套if优化_Java 如何优化if语句嵌套

    我们平时写if,switch或for语句是常有的事儿,也一定写过多层if或for语句嵌套的情况,如果代码里的嵌套超过3层,阅读起来就会非常困难了.我们应该尽量避免代码嵌套多层,最好不要超过2层. if ...

  9. java上机实验答案_java上机实验答案与解析

    java上机实验答案与解析 JAVA上机实验题答案与解析 实验一 Java程序编程 1. 编写一个Java应用程序,输出内容为Hello!. 注:文件位置位于e:\2:\Hello.java 编译:( ...

最新文章

  1. [转载]Linux用户管理全攻略(八)
  2. 移动端适配与响应式布局
  3. [vue] SSR解决了什么问题?有做过SSR吗?你是怎么做的?
  4. html文本框样式大全,HTML文本框样式大全
  5. 北京人工智能工程师职称评定政策出台,明年起一年一评
  6. Multiload-ng
  7. Laravel 安装mysql、表增加模拟数据、生成控制器
  8. 工作流 节点子线程_节点JS体系结构–单线程事件循环
  9. 【java集合框架源码剖析系列】java源码剖析之TreeSet
  10. 解决windows server2012 评估版本过期,系统自动关机 重启
  11. 浅读C Primer Plus——C语起源
  12. 素数判断 isPrime
  13. 计算机为啥启用不了网络发现,Win7系统网络发现打不开怎么办 win7不能启用网络发现如何解决...
  14. 数据库系统之物理设计
  15. 海明码(汉明码)详解
  16. U盘文件乱码的解决方案
  17. 如何用photoshop cs5的吸管工具
  18. [Python 爬虫]煎蛋网 OOXX 妹子图爬虫(1)——解密图片地址
  19. 在 JavaScript 中获取对象的第一个键名
  20. 利用正态分布进行异常点检测

热门文章

  1. scanf 函数的返回值
  2. webpack loader解析及自定义loader
  3. IPFS凭什么这么硬气?
  4. 外汇交易的最佳时间点
  5. 2023考研推荐新闻传播专业入门可以看的好书
  6. 工具使用——Burp与FoxyProxy Standard配置
  7. 视频业淘汰赛开始:爱奇艺遇新挑战
  8. 2021-12-15 虚拟机WMware windows7 安装WMware Tools安装向导提前结束。安装WMware Tools成功后客户机与宿主机可以复制文件和共享剪切板。
  9. 【CVPR2022】Lite Vision Transformer with Enhanced Self-Attention
  10. 数学建模——整数规划