在日志分析中,经常会对记录的sql进行分析,所以将一整行sql格式化,进行多行缩就显得很有必要,许多数据库客户端都提供sql的格式化功能,但复杂的多层嵌套sql往往格式化的l还不够友好,所以就自己造了个。

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;
import java.util.StringTokenizer; public class BasicFormatterImpl {
private static final Set<String> BEGIN_CLAUSES = new HashSet<String>();
private static final Set<String> END_CLAUSES = new HashSet<String>();
private static final Set<String> LOGICAL = new HashSet<String>();
private static final Set<String> QUANTIFIERS = new HashSet<String>();
private static final Set<String> DML = new HashSet<String>();
private static final Set<String> MISC = new HashSet<String>();
static final String indentString = " ";
static final String initial = "\n "; public String format(String source) {
return new FormatProcess(source).perform().trim();
} static {
BEGIN_CLAUSES.add("left");
BEGIN_CLAUSES.add("right");
BEGIN_CLAUSES.add("inner");
BEGIN_CLAUSES.add("outer");
BEGIN_CLAUSES.add("group");
BEGIN_CLAUSES.add("order"); END_CLAUSES.add("where");
END_CLAUSES.add("set");
END_CLAUSES.add("having");
END_CLAUSES.add("join");
END_CLAUSES.add("from");
END_CLAUSES.add("by");
END_CLAUSES.add("join");
END_CLAUSES.add("into");
END_CLAUSES.add("union"); LOGICAL.add("and");
LOGICAL.add("or");
LOGICAL.add("when");
LOGICAL.add("else");
LOGICAL.add("end"); QUANTIFIERS.add("in");
QUANTIFIERS.add("all");
QUANTIFIERS.add("exists");
QUANTIFIERS.add("some");
QUANTIFIERS.add("any"); DML.add("insert");
DML.add("update");
DML.add("delete"); MISC.add("select");
MISC.add("on");
} private static class FormatProcess {
boolean beginLine = true;
boolean afterBeginBeforeEnd = false;
boolean afterByOrSetOrFromOrSelect = false;
boolean afterValues = false;
boolean afterOn = false;
boolean afterBetween = false;
boolean afterInsert = false;
int inFunction = 0;
int parensSinceSelect = 0;
private LinkedList<Integer> parenCounts = new LinkedList<Integer>();
private LinkedList<Boolean> afterByOrFromOrSelects = new LinkedList<Boolean>(); int indent = 1; StringBuffer result = new StringBuffer();
StringTokenizer tokens;
String lastToken;
String token;
String lcToken; public FormatProcess(String sql) {
this.tokens = new StringTokenizer(sql, "()+*/-=<>'`\"[], \n\r\f\t", true);
} public String perform() {
this.result.append("\n "); while (this.tokens.hasMoreTokens()) {
this.token = this.tokens.nextToken();
this.lcToken = this.token.toLowerCase(); if ("'".equals(this.token)) {
String t;
do {
t = this.tokens.nextToken();
this.token += t;
} while ((!"'".equals(t)) && (this.tokens.hasMoreTokens()));
} else if ("\"".equals(this.token)) {
String t;
do {
t = this.tokens.nextToken();
this.token += t;
} while (!"\"".equals(t));
} if ((this.afterByOrSetOrFromOrSelect) && (",".equals(this.token))) {
commaAfterByOrFromOrSelect();
} else if ((this.afterOn) && (",".equals(this.token))) {
commaAfterOn();
} else if ("(".equals(this.token)) {
openParen();
} else if (")".equals(this.token)) {
closeParen();
} else if (BasicFormatterImpl.BEGIN_CLAUSES.contains(this.lcToken)) {
beginNewClause();
} else if (BasicFormatterImpl.END_CLAUSES.contains(this.lcToken)) {
endNewClause();
} else if ("select".equals(this.lcToken)) {
select();
} else if (BasicFormatterImpl.DML.contains(this.lcToken)) {
updateOrInsertOrDelete();
} else if ("values".equals(this.lcToken)) {
values();
} else if ("on".equals(this.lcToken)) {
on();
} else if ((this.afterBetween) && (this.lcToken.equals("and"))) {
misc();
this.afterBetween = false;
} else if (BasicFormatterImpl.LOGICAL.contains(this.lcToken)) {
logical();
} else if (isWhitespace(this.token)) {
white();
} else {
misc();
} if (!isWhitespace(this.token)) {
this.lastToken = this.lcToken;
}
} return this.result.toString();
} private void commaAfterOn() {
out();
this.indent -= 1;
newline();
this.afterOn = false;
this.afterByOrSetOrFromOrSelect = true;
} private void commaAfterByOrFromOrSelect() {
out();
newline();
} private void logical() {
if ("end".equals(this.lcToken)) {
this.indent -= 1;
}
newline();
out();
this.beginLine = false;
} private void on() {
this.indent += 1;
this.afterOn = true;
newline();
out();
this.beginLine = false;
} private void misc() {
out();
if ("between".equals(this.lcToken)) {
this.afterBetween = true;
}
if (this.afterInsert) {
newline();
this.afterInsert = false;
} else {
this.beginLine = false;
if ("case".equals(this.lcToken))
this.indent += 1;
}
} private void white() {
if (!this.beginLine)
this.result.append(" ");
} private void updateOrInsertOrDelete() {
out();
this.indent += 1;
this.beginLine = false;
if ("update".equals(this.lcToken)) {
newline();
}
if ("insert".equals(this.lcToken))
this.afterInsert = true;
} private void select() {
out();
this.indent += 1;
newline();
this.parenCounts.addLast(new Integer(this.parensSinceSelect));
this.afterByOrFromOrSelects.addLast(Boolean.valueOf(this.afterByOrSetOrFromOrSelect));
this.parensSinceSelect = 0;
this.afterByOrSetOrFromOrSelect = true;
} private void out() {
this.result.append(this.token);
} private void endNewClause() {
if (!this.afterBeginBeforeEnd) {
this.indent -= 1;
if (this.afterOn) {
this.indent -= 1;
this.afterOn = false;
}
newline();
}
out();
if (!"union".equals(this.lcToken)) {
this.indent += 1;
}
newline();
this.afterBeginBeforeEnd = false;
this.afterByOrSetOrFromOrSelect = (("by".equals(this.lcToken)) || ("set".equals(this.lcToken))
|| ("from".equals(this.lcToken)));
} private void beginNewClause() {
if (!this.afterBeginBeforeEnd) {
if (this.afterOn) {
this.indent -= 1;
this.afterOn = false;
}
this.indent -= 1;
newline();
}
out();
this.beginLine = false;
this.afterBeginBeforeEnd = true;
} private void values() {
this.indent -= 1;
newline();
out();
this.indent += 1;
newline();
this.afterValues = true;
} private void closeParen() {
this.parensSinceSelect -= 1;
if (this.parensSinceSelect < 0) {
this.indent -= 1;
this.parensSinceSelect = ((Integer) this.parenCounts.removeLast()).intValue();
this.afterByOrSetOrFromOrSelect = ((Boolean) this.afterByOrFromOrSelects.removeLast()).booleanValue();
}
if (this.inFunction > 0) {
this.inFunction -= 1;
out();
} else {
if (!this.afterByOrSetOrFromOrSelect) {
this.indent -= 1;
newline();
}
out();
}
this.beginLine = false;
} private void openParen() {
if ((isFunctionName(this.lastToken)) || (this.inFunction > 0)) {
this.inFunction += 1;
}
this.beginLine = false;
if (this.inFunction > 0) {
out();
} else {
out();
if (!this.afterByOrSetOrFromOrSelect) {
this.indent += 1;
newline();
this.beginLine = true;
}
}
this.parensSinceSelect += 1;
} private static boolean isFunctionName(String tok) {
char begin = tok.charAt(0);
boolean isIdentifier = (Character.isJavaIdentifierStart(begin)) || ('"' == begin);
return (isIdentifier) && (!BasicFormatterImpl.LOGICAL.contains(tok))
&& (!BasicFormatterImpl.END_CLAUSES.contains(tok))
&& (!BasicFormatterImpl.QUANTIFIERS.contains(tok)) && (!BasicFormatterImpl.DML.contains(tok))
&& (!BasicFormatterImpl.MISC.contains(tok));
} private static boolean isWhitespace(String token) {
return " \n\r\f\t".indexOf(token) >= 0;
} private void newline() {
this.result.append("\n");
for (int i = 0; i < this.indent; i++) {
this.result.append(" ");
}
this.beginLine = true;
}
} public static void main(String[] args) {
System.out.println(new BasicFormatterImpl()
.format("select aa,bb,cc,dd from ta1,(select ee,ff,gg from ta2 where ee=ff) ta3 where aa=bb and cc=dd group by dd order by createtime desc limit 3 "));
}
}

  

运行结果:

java格式化sql的更多相关文章

  1. mybatis自定义打印执行时间并格式化sql插件

    打印SQL的执行时间,我们可以实现mybatis官方我们提供的接口org.apache.ibatis.plugin.Interceptor,我们可以拦截的类有多个Executor,StatementH ...

  2. atitit.java解析sql语言解析器解释器的实现

    atitit.java解析sql语言解析器解释器的实现 1. 解析sql的本质:实现一个4gl dsl编程语言的编译器 1 2. 解析sql的主要的流程,词法分析,而后进行语法分析,语义分析,构建sq ...

  3. java连接sql server2000/2005

    接触Java或者JSP,难免会使用到数据库SQL Server 2000/2005(我使用2005标准版[9.0.3054]测试),经过自己的搜索和研究,使用JDBC连接SQL Server成功,特此 ...

  4. JAVA格式化时间日期

    JAVA格式化时间日期 import java.util.Date; import java.text.DateFormat; /** * 格式化时间类 * DateFormat.FULL = 0 * ...

  5. 使用java对sql server进行增删改查

    import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import ...

  6. jTDS Java连接SQL Server 2000数据库

    Java连接SQL Server 2000数据库时,有两种方法: (1)通过Microsoft的JDBC驱动连接.此JDBC驱动共有三个文件,分别 是mssqlserver.jar.msutil.ja ...

  7. 7.20.01 java格式化输出 printf 例子

    java格式化输出 printf 例子 importjava.util.Date; publicclassPrintf { publicstaticvoidmain(String[] args) { ...

  8. Java 获取SQL查询语句结果

    step1:构造连接Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnec ...

  9. Java格式化时间

    Java格式化时间 将秒或者毫秒值格式化成指定格式的时间 效果图 工具类 工具类里我只列出了一种格式的格式化方式,可以根据自己的需求,修改"yyyy-MM-dd hh:mm:ss" ...

随机推荐

  1. 2016/04/29 smarty模板 1, 初步 目标 : 变量 运算符 表达式 流程控制 函数

    ① 从配置文件中读取配置: 1,在模板页面加载配置文件 html页面 不是php页面 <{config_load file='fo.conf'}> 2,在需要用到配置的地方加 <{# ...

  2. bacth参数说明 cmd parameter

    http://www.robvanderwoude.com/parameters.php Windows NT 4 introduced a set of new features for comma ...

  3. Apache POI组件操作Excel,制作报表(四)

    Apache POI组件操作Excel,制作报表(四) 博客分类: 探索实践 ExcelApacheSpringMVCServlet      上一篇我们介绍了如何制作复杂报表的分析和设计,本篇结合S ...

  4. 信息检索导论的课件——http://home.ustc.edu.cn/~zhufengx/ir/pdf/

    http://home.ustc.edu.cn/~zhufengx/ir/pdf/ 中科大

  5. mac系统下设置eclipse的补全快捷键方法

    eclispe Word Completion 的默认快捷键是Alt+/eclipse Content Assist 的默认快捷键是Ctrl+Space在使用中发现Word Completion经常导 ...

  6. BZOJ4561: [JLoi2016]圆的异或并 计算几何+treap

    因为本题保证两圆之间只有相包含或相离(不用担心两圆重合 因为我没有RE) 所以每个圆之间的相对位置是确定的  也就是可以按极角排序的, 所以可以按横坐标排序后 扫描同时用treap维护加圆删圆(即遇到 ...

  7. css3 all属性

    ie不支持,谷歌火狐支持,safari9+支持,移动端高版本支持 all属性实际上是所有CSS属性的缩写,表示,所有的CSS属性都怎样怎样,但是,不包括unicode-bidi和direction这两 ...

  8. mysqlnd cannot connect to MySQL 4.1+ using old authentication

    报这个错误主要是因为mysql使用了老的密码格式,而程序要求使用新的格式导致的,解决办法: SET old_passwords = 0; UPDATE mysql.user SET Password ...

  9. 洛谷P3295 [SCOI2016]萌萌哒(倍增+并查集)

    传送门 思路太妙了啊…… 容易才怪想到暴力,把区间内的每一个数字用并查集维护相等,然后设最后总共有$k$个并查集,那么答案就是$9*10^{k-1}$(因为第一位不能为0) 考虑倍增.我们设$f[i] ...

  10. ntp多台主机时间同步

    通俗的讲,多台主机ntp时间同步,就是自定义集群中一台机器(我们这里叫它server)与网络时间同步,然后其它主机与server主机时间同步 另外,ntp时间同步机制不是我们想象的那样直接同步,而是“ ...