--- layout: post title: SQL 拼接 tags: sql database Java categories: database published: true --- 在java中进行SQL拼接是一件无比痛苦的工作,这是由于需要通过判断参数动态生成SQL 而且拼接时产生满屏幕的加号或者append,使SQL几乎失去了可读性,那么丢失`WHERE`,`AND`,逗号等语法错误将随之而来 最近研究mybatis时发现了一个非常好用的工具类 SQL Builder [^sqlBuilder] ## 示例 ~~~java @Test public void test(){ String sql = new SQL(){ { SELECT("name"); SELECT("password"); SELECT("sex"); FROM("student s"); INNER_JOIN("info i on s.id = i.id"); WHERE(String.format("name = '%s'","HanMeiMei")); } }.toString(); System.out.println(sql); } ~~~ 运行结果为: SELECT name, password, sex FROM student s INNER JOIN info i on s.id = i.id WHERE (name = 'HanMeiMei' AND i.sex = 1) SQL的拼接词都自动生成了 ## 源码 事实上不必为了使用这个类而引入Mybatis,SQL Builder非常简单,简单到没有使用任何第三方类库,只需将这个类复制粘贴一下就可以直接用了。 SQL Builder 全部代码 ~~~java import java.io.IOException; import java.util.ArrayList; import java.util.List; public abstract class AbstractSQL { private static final String AND = ") \nAND ("; private static final String OR = ") \nOR ("; public abstract T getSelf(); public T UPDATE(String table) { sql().statementType = SQLStatement.StatementType.UPDATE; sql().tables.add(table); return getSelf(); } public T SET(String sets) { sql().sets.add(sets); return getSelf(); } public T INSERT_INTO(String tableName) { sql().statementType = SQLStatement.StatementType.INSERT; sql().tables.add(tableName); return getSelf(); } public T VALUES(String columns, String values) { sql().columns.add(columns); sql().values.add(values); return getSelf(); } public T SELECT(String columns) { sql().statementType = SQLStatement.StatementType.SELECT; sql().select.add(columns); return getSelf(); } public T SELECT_DISTINCT(String columns) { sql().distinct = true; SELECT(columns); return getSelf(); } public T DELETE_FROM(String table) { sql().statementType = SQLStatement.StatementType.DELETE; sql().tables.add(table); return getSelf(); } public T FROM(String table) { sql().tables.add(table); return getSelf(); } public T JOIN(String join) { sql().join.add(join); return getSelf(); } public T INNER_JOIN(String join) { sql().innerJoin.add(join); return getSelf(); } public T LEFT_OUTER_JOIN(String join) { sql().leftOuterJoin.add(join); return getSelf(); } public T RIGHT_OUTER_JOIN(String join) { sql().rightOuterJoin.add(join); return getSelf(); } public T OUTER_JOIN(String join) { sql().outerJoin.add(join); return getSelf(); } public T WHERE(String conditions) { sql().where.add(conditions); sql().lastList = sql().where; return getSelf(); } public T OR() { sql().lastList.add(OR); return getSelf(); } public T AND() { sql().lastList.add(AND); return getSelf(); } public T GROUP_BY(String columns) { sql().groupBy.add(columns); return getSelf(); } public T HAVING(String conditions) { sql().having.add(conditions); sql().lastList = sql().having; return getSelf(); } public T ORDER_BY(String columns) { sql().orderBy.add(columns); return getSelf(); } private SQLStatement sql = new SQLStatement(); private SQLStatement sql() { return sql; } public A usingAppender(A a) { sql().sql(a); return a; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sql().sql(sb); return sb.toString(); } private static class SafeAppendable { private final Appendable a; private boolean empty = true; public SafeAppendable(Appendable a) { super(); this.a = a; } public SafeAppendable append(CharSequence s) { try { if (empty && s.length() > 0) empty = false; a.append(s); } catch (IOException e) { throw new RuntimeException(e); } return this; } public boolean isEmpty() { return empty; } } private static class SQLStatement { public enum StatementType { DELETE, INSERT, SELECT, UPDATE } StatementType statementType; List sets = new ArrayList(); List select = new ArrayList(); List tables = new ArrayList(); List join = new ArrayList(); List innerJoin = new ArrayList(); List outerJoin = new ArrayList(); List leftOuterJoin = new ArrayList(); List rightOuterJoin = new ArrayList(); List where = new ArrayList(); List having = new ArrayList(); List groupBy = new ArrayList(); List orderBy = new ArrayList(); List lastList = new ArrayList(); List columns = new ArrayList(); List values = new ArrayList(); boolean distinct; private void sqlClause(SafeAppendable builder, String keyword, List parts, String open, String close, String conjunction) { if (!parts.isEmpty()) { if (!builder.isEmpty()) builder.append("\n"); builder.append(keyword); builder.append(" "); builder.append(open); String last = "________"; for (int i = 0, n = parts.size(); i < n; i++) { String part = parts.get(i); if (i > 0 && !part.equals(AND) && !part.equals(OR) && !last.equals(AND) && !last.equals(OR)) { builder.append(conjunction); } builder.append(part); last = part; } builder.append(close); } } private String selectSQL(SafeAppendable builder) { if (distinct) { sqlClause(builder, "SELECT DISTINCT", select, "", "", ", "); } else { sqlClause(builder, "SELECT", select, "", "", ", "); } sqlClause(builder, "FROM", tables, "", "", ", "); sqlClause(builder, "JOIN", join, "", "", "\nJOIN "); sqlClause(builder, "INNER JOIN", innerJoin, "", "", "\nINNER JOIN "); sqlClause(builder, "OUTER JOIN", outerJoin, "", "", "\nOUTER JOIN "); sqlClause(builder, "LEFT OUTER JOIN", leftOuterJoin, "", "", "\nLEFT OUTER JOIN "); sqlClause(builder, "RIGHT OUTER JOIN", rightOuterJoin, "", "", "\nRIGHT OUTER JOIN "); sqlClause(builder, "WHERE", where, "(", ")", " AND "); sqlClause(builder, "GROUP BY", groupBy, "", "", ", "); sqlClause(builder, "HAVING", having, "(", ")", " AND "); sqlClause(builder, "ORDER BY", orderBy, "", "", ", "); return builder.toString(); } private String insertSQL(SafeAppendable builder) { sqlClause(builder, "INSERT INTO", tables, "", "", ""); sqlClause(builder, "", columns, "(", ")", ", "); sqlClause(builder, "VALUES", values, "(", ")", ", "); return builder.toString(); } private String deleteSQL(SafeAppendable builder) { sqlClause(builder, "DELETE FROM", tables, "", "", ""); sqlClause(builder, "WHERE", where, "(", ")", " AND "); return builder.toString(); } private String updateSQL(SafeAppendable builder) { sqlClause(builder, "UPDATE", tables, "", "", ""); sqlClause(builder, "SET", sets, "", "", ", "); sqlClause(builder, "WHERE", where, "(", ")", " AND "); return builder.toString(); } public String sql(Appendable a) { SafeAppendable builder = new SafeAppendable(a); if (statementType == null) { return null; } String answer; switch (statementType) { case DELETE: answer = deleteSQL(builder); break; case INSERT: answer = insertSQL(builder); break; case SELECT: answer = selectSQL(builder); break; case UPDATE: answer = updateSQL(builder); break; default: answer = null; } return answer; } } } public class SQL extends AbstractSQL { @Override public SQL getSelf() { return this; } } ~~~ [^sqlBuilder]: [http://mybatis.github.io/mybatis-3/statement-builders.html](http://mybatis.github.io/mybatis-3/statement-builders.html)