1:有时候我们需要动态生成SQL语句,我们当然可以在代码中直接写出那条SQL语句,然而令人头疼的是对于SQL语句的各种换行,格式化,逗号,AND和OR的处理,都是很容易出错的,对此,需要有一个更加智能的方式方便我们编写SQL语句。
2:MyBatis提供了一个好用的工具类帮助我们解决这个问题,其文档地址为:
Mybatis SQL 语句构建器
本文仿造Mybatis,模仿实现了一个基于C++语言版的SQL语句构建器。
首先需要一个拼接SQL语句的类
SQLStatement.hpp
#include
#include
#include
/**
* 封装SQL句
*/
class SQLStatement {
friend class SQLBuilder;
private:
const std::string AND = ") AND (";
const std::string OR = ") OR (";
/**
* 语句类型:增删改查
*/
enum class StatementType {
DELETE, INSERT, SELECT, UPDATE
} statementType;
std::vector<std::string> sets;
std::vector<std::string> select;
std::vector<std::string> tables;
std::vector<std::string> join;
std::vector<std::string> innerJoin;
std::vector<std::string> outerJoin;
std::vector<std::string> leftOuterJoin;
std::vector<std::string> rightOuterJoin;
std::vector<std::string> where;
std::vector<std::string> having;
std::vector<std::string> groupBy;
std::vector<std::string> orderBy;
std::vector<std::string> *lastList = nullptr;
std::vector<std::string> columns;
std::vector<std::vector<std::string>> valuesList;//插入
bool distinct = false;
std::string offset;
std::string limit;
public:
SQLStatement() {
//初始化,插入值有一行
valuesList.resize(1);
}
private:
void sqlClause(std::string &builder, const std::string &keyword, const std::vector<std::string> &parts,
const std::string &open, const std::string &close, const std::string &conjunction) {
if (parts.empty()) {
return;
}
if (!builder.empty()) {
builder.append(" ");
}
builder.append(keyword);
builder.append(" ");
builder.append(open);
std::string last = "";
for (int i = 0, n = parts.size(); i < n; i++) {
std::string part = parts.at(i);
if (i > 0 && part != AND && part != OR && last != AND && last != OR) {
builder.append(conjunction);
}
builder.append(part);
last = part;
}
builder.append(close);
}
void deleteSQL(std::string &builder) {
sqlClause(builder, "DELETE FROM", tables, "", "", "");
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
appendLimitClause(builder, "", limit);
}
void updateSQL(std::string &builder) {
sqlClause(builder, "UPDATE", tables, "", "", "");
joins(builder);
sqlClause(builder, "SET", sets, "", "", ", ");
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
appendLimitClause(builder, "", limit);
}
void insertSQL(std::string &builder) {
sqlClause(builder, "INSERT INTO", tables, "", "", "");
sqlClause(builder, "", columns, "(", ")", ", ");
for (int i = 0; i < valuesList.size(); i++) {
sqlClause(builder, i > 0 ? "," : "VALUES", valuesList.at(i), "(", ")", ", ");
}
}
void joins(std::string &builder) {
sqlClause(builder, "JOIN", join, "", "", " JOIN ");
sqlClause(builder, "INNER JOIN", innerJoin, "", "", " INNER JOIN ");
sqlClause(builder, "OUTER JOIN", outerJoin, "", "", " OUTER JOIN ");
sqlClause(builder, "LEFT OUTER JOIN", leftOuterJoin, "", "", " LEFT OUTER JOIN ");
sqlClause(builder, "RIGHT OUTER JOIN", rightOuterJoin, "", "", " RIGHT OUTER JOIN ");
}
void appendLimitClause(std::string &builder, const std::string &offset, const std::string &limit) {
if (!limit.empty()) {
builder.append(" LIMIT ").append(limit);
}
if (!offset.empty()) {
builder.append(" OFFSET ").append(offset);
}
}
void selectSQL(std::string &builder) {
if (distinct) {
sqlClause(builder, "SELECT DISTINCT", select, "", "", ", ");
} else {
sqlClause(builder, "SELECT", select, "", "", ", ");
}
sqlClause(builder, "FROM", tables, "", "", ", ");
joins(builder);
sqlClause(builder, "WHERE", where, "(", ")", " AND ");
sqlClause(builder, "GROUP BY", groupBy, "", "", ", ");
sqlClause(builder, "HAVING", having, "(", ")", " AND ");
sqlClause(builder, "ORDER BY", orderBy, "", "", ", ");
appendLimitClause(builder, offset, limit);
}
private:
std::string sql() {
std::string answer;
switch (statementType) {
case StatementType::DELETE:
deleteSQL(answer);
break;
case StatementType::INSERT:
insertSQL(answer);
break;
case StatementType::SELECT:
selectSQL(answer);
break;
case StatementType::UPDATE:
updateSQL(answer);
break;
default:
answer = "";
}
return answer;
}
};
SQL构建器接口实现
SQLBuilder.hpp
#include
#include "SQLStatement.hpp"
/**
* sql语句构建器
*/
class SQLBuilder {
private:
SQLStatement sql;
public:
SQLBuilder &UPDATE(const std::string &table) {
sql.statementType = SQLStatement::StatementType::UPDATE;
sql.tables.emplace_back(table);
return *this;
}
SQLBuilder &SET(const std::string &sets) {
sql.sets.emplace_back(sets);
return *this;
}
SQLBuilder &INSERT_INTO(const std::string &tableName) {
sql.statementType = SQLStatement::StatementType::INSERT;
sql.tables.emplace_back(tableName);
return *this;
}
SQLBuilder &VALUES(const std::string &columns, const std::string &values) {
INTO_COLUMNS(columns);
INTO_VALUES(values);
return *this;
}
SQLBuilder &INTO_COLUMNS(const std::string &columns) {
sql.columns.emplace_back(columns);
return *this;
}
SQLBuilder &INTO_VALUES(const std::string &values) {
sql.valuesList.back().emplace_back(values);
return *this;
}
SQLBuilder &SELECT(const std::string &columns) {
sql.statementType = SQLStatement::StatementType::SELECT;
sql.select.emplace_back(columns);
return *this;
}
SQLBuilder &SELECT_DISTINCT(const std::string &columns) {
sql.distinct = true;
return SELECT(columns);
}
SQLBuilder &DELETE_FROM(const std::string &table) {
sql.statementType = SQLStatement::StatementType::DELETE;
sql.tables.emplace_back(table);
return *this;
}
SQLBuilder &FROM(const std::string &table) {
sql.tables.emplace_back(table);
return *this;
}
SQLBuilder &JOIN(const std::string &join) {
sql.join.emplace_back(join);
return *this;
}
SQLBuilder &INNER_JOIN(const std::string &join) {
sql.innerJoin.emplace_back(join);
return *this;
}
SQLBuilder &LEFT_OUTER_JOIN(const std::string &join) {
sql.leftOuterJoin.emplace_back(join);
return *this;
}
SQLBuilder &RIGHT_OUTER_JOIN(const std::string &join) {
sql.rightOuterJoin.emplace_back(join);
return *this;
}
SQLBuilder &OUTER_JOIN(const std::string &join) {
sql.outerJoin.emplace_back(join);
return *this;
}
SQLBuilder &WHERE(const std::string &conditions) {
sql.where.emplace_back(conditions);
sql.lastList = &sql.where;
return *this;
}
SQLBuilder &OR() {
sql.lastList->emplace_back(sql.OR);
return *this;
}
SQLBuilder &AND() {
sql.lastList->emplace_back(sql.AND);
return *this;
}
SQLBuilder &GROUP_BY(const std::string &columns) {
sql.groupBy.emplace_back(columns);
return *this;
}
SQLBuilder &HAVING(const std::string &conditions) {
sql.having.emplace_back(conditions);
sql.lastList = &sql.having;
return *this;
}
SQLBuilder &ORDER_BY(const std::string &columns) {
sql.orderBy.emplace_back(columns);
return *this;
}
SQLBuilder &LIMIT(const std::string &variable, const std::string &offset) {
sql.limit = variable;
sql.offset = offset;
return *this;
}
SQLBuilder &LIMIT(const std::string &variable) {
sql.limit = variable;
sql.offset = std::to_string(0);
return *this;
}
/**
* 批量插入时,多插入一行
* @return
*/
SQLBuilder &ADD_ROW() {
sql.valuesList.resize(sql.valuesList.size() + 1);
return *this;
}
std::string toString() {
return sql.sql();
}
};
#include "SQLBuilder.hpp"
int main() {
auto sql1 = SQLBuilder()
.SELECT("P.ID, P.USERNAME, P.PASSWORD, P.FULL_NAME")
.SELECT("P.LAST_NAME, P.CREATED_ON, P.UPDATED_ON")
.FROM("PERSON P")
.FROM("ACCOUNT A")
.INNER_JOIN("DEPARTMENT D on D.ID = P.DEPARTMENT_ID")
.INNER_JOIN("COMPANY C on D.COMPANY_ID = C.ID")
.WHERE("P.ID = A.ID")
.WHERE("P.FIRST_NAME like ?")
.OR()
.WHERE("P.LAST_NAME like ?")
.GROUP_BY("P.ID")
.HAVING("P.LAST_NAME like ?")
.OR()
.HAVING("P.FIRST_NAME like ?")
.ORDER_BY("P.ID")
.ORDER_BY("P.FULL_NAME")
.LIMIT("?", "?")
.toString();
auto sql2 = SQLBuilder()
.INSERT_INTO("PERSON")
.VALUES("ID, FIRST_NAME", "?, ?")
.VALUES("LAST_NAME", "?")
.toString();
auto sql3 = SQLBuilder()
.INSERT_INTO("TABLE_A")
.INTO_COLUMNS("a,b,c,d")
.INTO_VALUES("1,2,3,4")
.ADD_ROW()
.INTO_VALUES("5,6")
.INTO_VALUES("7,8")
.toString();
auto sql4 = SQLBuilder()
.DELETE_FROM("PERSON")
.WHERE("id=?")
.LIMIT("20")
.toString();
auto sql5 = SQLBuilder()
.UPDATE("PERSON")
.SET("name=?")
.WHERE("id=10")
.toString();
return 0;
}