Files
kaka111222333-kaka111222333…/_posts/2015-02-13-sqlappend.md
2019-11-17 01:12:14 +08:00

341 lines
8.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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的拼接词都自动生成了
## 源码
事实上不必为了使用这个类而引入MybatisSQL Builder非常简单简单到没有使用任何第三方类库只需将这个类复制粘贴一下就可以直接用了。
SQL Builder 全部代码
~~~java
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public abstract class AbstractSQL<T> {
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 extends Appendable> 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<String> sets = new ArrayList<String>();
List<String> select = new ArrayList<String>();
List<String> tables = new ArrayList<String>();
List<String> join = new ArrayList<String>();
List<String> innerJoin = new ArrayList<String>();
List<String> outerJoin = new ArrayList<String>();
List<String> leftOuterJoin = new ArrayList<String>();
List<String> rightOuterJoin = new ArrayList<String>();
List<String> where = new ArrayList<String>();
List<String> having = new ArrayList<String>();
List<String> groupBy = new ArrayList<String>();
List<String> orderBy = new ArrayList<String>();
List<String> lastList = new ArrayList<String>();
List<String> columns = new ArrayList<String>();
List<String> values = new ArrayList<String>();
boolean distinct;
private void sqlClause(SafeAppendable builder, String keyword, List<String> 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<SQL> {
@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)