java格式化sql

在日志分析中,经常会对记录的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 "));
	}
}

  

运行结果:

时间: 2024-10-11 05:32:18

java格式化sql的相关文章

Java执行SQL脚本导入

今天做了一个用java导入sql脚本的功能,前台上传一个sql文件,后台先保存本地,然后进行导入.主要代码如下: String cmd = "cmd /c sqlplus usr/[email protected]{//服务器IP:1521/}sid @d:\\1.sql>d:\\t.log"; Process p = null; try {     p = Runtime.getRuntime().exec(cmd); } catch (IOException e) {    

【转】java格式化输出 printf 例子

[转]java格式化输出 printf 例子 转自http://www.cnblogs.com/TankMa/archive/2011/08/20/2146913.html#undefined import java.util.Date; /** * 使用printf输出 */ /**关键技术点 * 使用java.io.PrintStream的printf方法实现C风格的输出 * printf 方法的第一个参数为输出的格式,第二个参数是可变长的,表示待输出的数据对象 */ public clas

java连接Sql server 2005

最近在做老师布置的SQL Server大作业,其中有一道题就是用java连接SQL Server.以前连接数据库都是在MyEclipse中完成的.这次我换用记事本连接.下面是我的步骤: 1.首先,下载java连接SQL Server的驱动:sqljdbc 2.解压之后,找到sqljdbc.jar的所在位置,我的是:D:\Program Files (x86)\sqljdbc\sqlDriver\sqlDriver 3.配置环境变量:在系统的classpath中将sqljdbc.jar的文件位置添

一个简单的Java 连接SQL Server数据库连接驱动类

import java.sql.*; /** * SQL Server数据库连接类 * @author Administrator * */ public class Sqlsdc { static int a = 0; public Connection sqlsdc(String user, String pwd, String dn) { String url = "jdbc:sqlserver://localhost:1433;databaseName="+dn; final

Java连接SQL Server:jTDS驱动兼容性问题

Java连接SQL Server 2000数据库时,有两种方法: (1)通过Microsoft的JDBC驱动连接.此JDBC驱动共有三个文件,分别是mssqlserver.jar.msutil.jar和msbase.jar.但是Microsoft官网上已经找不到这些驱动,其提供的sqljdbc.jar和sqljdbc4.jar并不支持SQL Server 2000. 驱动程序名称:com.microsoft.jdbc.sqlserver.SQLServerDriver(即下面的classforn

关于 Java连接sql的转载

Java连接SQL Server 2000数据库时,有两种方法: (1)通过Microsoft的JDBC驱动连接.此JDBC驱动共有三个文件,分别是mssqlserver.jar.msutil.jar和msbase.jar.但是Microsoft官网上已经找不到这些驱动,其提供的sqljdbc.jar和sqljdbc4.jar并不支持SQL Server 2000. 驱动程序名称:com.microsoft.jdbc.sqlserver.SQLServerDriver(即下面的classforn

java连接sql server 2008的问题(jdbc驱动的方法)

这是程序代码,我是按照网上和视频讲解的步骤写的代码:import java.sql.*;public class jdbc {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubConnection ct = null;PreparedStatement ps = null;ResultSet rs = null;try {//第一步,加载驱动Class.forNa

Java 获取SQL查询语句结果

step1:构造连接Class.forName("com.mysql.jdbc.Driver"); Connection con = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/db","root","123"); step2:构造语句String sql = "select username,password from t_user where

jTDS Java连接SQL Server 2000数据库

Java连接SQL Server 2000数据库时,有两种方法: (1)通过Microsoft的JDBC驱动连接.此JDBC驱动共有三个文件,分别 是mssqlserver.jar.msutil.jar和msbase.jar.但是Microsoft官网上已经找不到这些驱动,其提供的 sqljdbc.jar和sqljdbc4.jar并不支持SQL Server 2000. 驱动程序名称:com.microsoft.jdbc.sqlserver.SQLServerDriver(即下面的classfo